Proximity or Manual Detection of Nearest Location

Post your questions and help other users.

Moderator: Martin

wired4sound
Posts: 20
Joined: 23 Jan 2019 21:02

Re: Proximity or Manual Detection of Nearest Location

Post by wired4sound » 29 Jan 2019 04:51

I managed to parse the CSV which is {database}

Now I want to add to each entry the distance from my office location (database[56],database[57] is where lat and long is) to my current location (location,) but instead of overwriting it each time I run the checks, it adds a new distance and I end up with multiple. I need it to overwrite the previous distances.

I can manage the rest

The concept is this:

1) park at one of 150 locations.
2) execute flow
3) flow tells me which office I am at with some information and allowing me access to respective office's data via a set of variables for other flows to perform
4) when done, before I leave;
a list of the next 10 locations pop up, allowing me to select which location I am heading to and also showing access to respective location's data via a set of variables for the office I selected (phone number to call, contact info, etc)
5) opening up map to select location

I can manage most of this but having trouble front the distance information to add respective locations so I can work with the data

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: Proximity or Manual Detection of Nearest Location

Post by Desmanto » 29 Jan 2019 16:53

column 56 and 57? That is a big csv.

Where do you add the result of distance calculation? I assume you add it a new glovar list to store it. So at first run, your glovar will have 150 distances. 2nd run and after, glovar now become 300, 450, 600, .... You want the glovar always stay 150 distances, right?

In that case, simply init the glovar back again at every execution.

Code: Select all

global_distances = newList();
That way, you glovar always start clean from empty and always result in 150 distance per run.


The next 10 location is random or closest ones? If random, just use getRandomElement(). You can copyList() first and remove the current office location, so you won't get the same current office location as the next destination.
But if next 10 is closest, in order to get the 10 closest location, you must sort the distances.

The sort() function is direct modifier, means the list is directly sorted and saved to the same list object. If you still need to maintain the original order of the distances calculation result, you have to copy the list before sort it.
sorted_dis = sort(copyList(global_distances), true, true);
This way, {sorted_dis} is the sorted version, starting from the closest until the furthest. While the original order of the global_distances is intact (which you can check the index later). This is needed later for the reverse lookup after you choose the location.

You can then access sorted_dis[9] (element 10th) to get the distances value at there. Loop against the global_distances and find if the value is smaller than sorted_dis[9], add the index of database to the next 10 choices.

After you have choosen the next location, you can retrieve the coordinate and use Start Activity, choose the example Google Maps with coordinate.
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

wired4sound
Posts: 20
Joined: 23 Jan 2019 21:02

Re: Proximity or Manual Detection of Nearest Location

Post by wired4sound » 29 Jan 2019 18:39

Yeah, It's pretty large, a lot of columns. I'll probably work on trimming it down once I get functionality working and go back and tidy things up. Just getting it working with bare minimum for now, as with many things so I can move away from tasker.

Once working, i go back and clean/tweak things up a bit.

I thought addElement would add another entry ("column") to the list ("row") so then I could access the current distance from my current location to each office at database[58] (the last entry)



150 is just the number of offices I have. Well, 153 now. I add one or 2 each quarter. So the number of distances would be the number of offices I currently have.

I will give all this info a try and report back.

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: Proximity or Manual Detection of Nearest Location

Post by Desmanto » 30 Jan 2019 17:41

It is not recommended to modify the list while you use it to loop. You will get concurrent modification error. That's why I use other list to store the element addition.
But since your database is a nested list, you loop upon the first level (the row) and add to the column of the row iteration, it seems to be no problem.

You can use if to check if the column 58 exists or not. Or just simply check the length, is it 59 (0-58). If yes, the don't add, simply assign the element, i[58] = distance. If no, then add, addElement(i, distance).
But since you have fixed number of element, you don't need to check anymore. Just reserved an empty column for index 58. When you export the csv, make sure that column exist. You can just put space or simply use formula ="" (equal to blank string) in the cell, to make sure it is occupied, but contain nothing. Then when you want to store the distance, no need to addElement(), always use assign value, i[58] = distance. That way, your distance will be always replaced, not added.

Looking from the variable you use, I construct a possible script for you. Assume that the database is the nested list converted from the csv.

Code: Select all

for(i in database)
{
  csvloc = newLocation(i[56], i[57]); //create csv location based on the csv lat long at column 56 and 57
  distance = round(distance(location, csvloc)); //calculate the distance of csvloc to current location
  i[58] = distance; //assignt the distance to column 58 of the current row iteration
}
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

wired4sound
Posts: 20
Joined: 23 Jan 2019 21:02

Re: Proximity or Manual Detection of Nearest Location

Post by wired4sound » 31 Jan 2019 13:13

How do I skip the first iteration?

I've tried a number of things with if and that doesn't seem to work. skip doesn't seem to work. i++ doesn't work so I try setting i to 1 if its 0 but that doesn't seem to work. Tried to only execute only if i !=0. I've looked at javascript syntax, java syntax, python syntax trying to figure it out.

Do you have documentation on this?

I need to skip the first iteration because there is math involved to convert meters to miles but the first iteration is just the headers and it's trying to execute math on the headers and throwing errors.

Code: Select all

for (i in database)
{
  
//if statement to make sure it skips database[0] since they are just headers
   
     csvloc=newLocation(i[36],i[37]);
     distance = round(distance(location, csvloc)*.000621);
     i[35] = distance; 
 

}

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: Proximity or Manual Detection of Nearest Location

Post by Desmanto » 31 Jan 2019 18:24

For example of script, you can look at Automagic's own example : https://automagic4android.com/automagic ... mples.html

I have actually document some of my own techniques, but scattered around this forum. Some are accessible from my index. I planned to summarize them all into single thread, it is also good for my own purpose too. Because sometimes I use the script only once, hence forget the pattern which I may try and error for hours to get it right.

Automagic is not full fledged programming language, so not all the featue from standard programming language work properly. There is no i++ support yet (it has been requested), you must use i = i + 1;

You don't need to skip the first iteration, although you can, by using if(). The better way is to remove the first row altogether, before starting the loop. So if your database first element is header, simply remove the index 0 element.

Code: Select all

removeElement(database, 0);
This will remove the first element (first header row). But you might want to reuse the header later, when saving the result back to file. So it is better to assign the removed element directly. removeElement() return the value of the removed element, so we assign it immediately.

Code: Select all

header = removeElement(database, 0);
Now the first header row is remove from database and stored in {header}. You can add it back later before saving it by using

Code: Select all

addElement(database, 0, header);
In case you still want to use the if() format, you can check if the i[36] or i[37] is a string (header must be string, not number), using isString(). if yes, continue (means skip this iteration)

Code: Select all

for (i in database)
{
     if(isString(i[36]))
          continue;
     csvloc=newLocation(i[36],i[37]);
     distance = round(distance(location, csvloc)*.000621);
     i[35] = distance; 
}
But why add the if(), if the first element can be easily removed (and readded) using the removeElement()


As for the method to loop, the one we use here for(i in database). There is another way to loop using the index, until the length of the list - 1. The difference is you have mention the database, becomes longer.

Code: Select all

header = removeElement(database, 0);
for (i in [0 to length(database)-1])
{
     csvloc=newLocation(database[i][36],database[i][37]);
     distance = round(distance(location, csvloc)*.000621);
     database[i][35] = distance; 
}
But even longer, this method allow you use the index as the order index to access multiple list at once. So probably you store another database which has the same length, you can do both operation at single index loop.
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

wired4sound
Posts: 20
Joined: 23 Jan 2019 21:02

Re: Proximity or Manual Detection of Nearest Location

Post by wired4sound » 31 Jan 2019 20:24

I ended up going with your second option. Much better idea for my use case as I may use header values to store respective variables for easier access later. Distance = i[35] to allow me to use Distance[x] to access distance values.

You mentioned sort values but it only seems to sort the element itself

How do I get it to sort based on a specific object. such as database[35] where all the distances are. From smallest to largest. So that first element ("row") database[0][35] is the shortest distance (the one closest to me) database[1][35] is the next shortest, etc without changing the order of the objects("columns") within the elements.

This lingo conversion isn't helping me. lol. Searching google and forums, etc often after you give me advise, I am able to use your examples or search other examples since then I know what I am looking for.

Nonetheless, I appreciate you helping and Automagic is blessed to have you helping out their community so much.

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: Proximity or Manual Detection of Nearest Location

Post by Desmanto » 01 Feb 2019 17:43

Not sure if you mean to create a new temporary list to hold the value and sort it there. Or you prefer to sort the whole database, based on column distance, but without moving the distance to the first column. I will just show both.

Store the distance in a new list
If you want to have separate list to maintain the sort, you can "export" the distance to new list.

Code: Select all

dislist = newList();
for(i in database)
  addElement(dislist, [i][35]);
sort(dislist, true, true);

chosenindex = 3;
for(i in database)
{
  if(i[35] == dislist[choosenindex])
    rowchosen = i;
}
This is using element looping, it add each entry in the column 35 to the new list {dislist}. Then to trace back to the original order, we can do this by comparing the value of the chosenindex from sorted list back to the database. If the same, means that is the row before sorted, take that row as the input. However this has some problem. Even there is small chance, but there is possibility that from 150 distances, there are same distance value, especially if you round it. When that happen, you will take risk of choosing the wrong duplicate distance when comparing the rowchosen. It will always pick the last row of the duplicate value. Beside, it is quite ugly to retrieve the index using the for(), then if(). I show this way to mark it as wrong way, so we don't use it. (and avoid it)

Store the index
So we have to store some extra index, to denotes that possible duplicate element is different, that is to store the row index. We can't use element looping, we must use index looping (although it is also possible to do with element looping), so we have the index number per loop. We also can't use map object, since there are possible duplicates value (map doesn't allow duplicate key).

Code: Select all

dislist = newList();
for(i in [0 to length(database)-1])
  addElement(dislist, newList(database[i][35], i));
sort(dislist, true, true);

chosenindex = 3;
rowchosen = database[dislist[chosenindex][1]]
The difference is the new list is a nested list with 2 elements. The first column is the distance, the second is the original row number from the database. Since we store the original row number, we can access it anytime even the first column is sorted or reversed. For chosenindex 3, to retrieve the original row number, we use dislist[3][1]; for example it is 42. The last row will evaluate to database[42] then, the row which contain the 4 shortest distance (chosenindex 3).

Using this method, your database row and column order is kept intact, but you need to store that dislist into somewhere else if you need to reuse it later.

Sort the database directly
It is possible to sort the database directly based on the column 35. But you have to move it first to first column, sort it, then move back to the column 35. I remember ever need to do something like this, but i just found out the method below which is much better and shorter than I remembered.

Code: Select all

//move column 36 to column 1
for(i in database)
  addElement(i, 0, removeElement(i, 35));

sort(database, true, true);

//move back column 1 to column 36
for(i in database)
   addElement(i, 35, removeElement(i, 0));
removeElement(i, 35) will remove the column 36. And because it returns the removed element, we can feed this back to addElement(), hence effectively move it from column 36 to column 1. Sort the value. And do the opposite to move back to the original column.

The end result is your database row order is sorted based on column index 35 (column 36). Column order is intact. There is no need to store separate distance list.


I am also grateful to have Automagic as a wonderful app that really helps me in daily activity. :)
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

wired4sound
Posts: 20
Joined: 23 Jan 2019 21:02

Re: Proximity or Manual Detection of Nearest Location

Post by wired4sound » 02 Feb 2019 16:48

Thanks for that.

I was trying to use something like

sort(database[35], true, true);

and sort(database, true, true)[35];

and

sort(database[35], true, true);

Would be nice to be able to specify which to sort by instead of having to rearrange

However, lucky for me, in my situation, [0] is already useless data.

I just put distance in [0] instead of in [35] to save having to manipulate later. Saves me time for having to modify the csv before the import and less resources used up in the flow itself. I just overwrite that first column instead.

Some lingo cheat sheets would be nice

pause/wait = sleep
row = element
column = object(?)

Etc, to help others that are coming from other platforms/programs/languages etc.

User avatar
Desmanto
Posts: 2709
Joined: 21 Jul 2017 17:50

Re: Proximity or Manual Detection of Nearest Location

Post by Desmanto » 02 Feb 2019 17:50

I think sorting directly by certain column is not possible. Automagic see the 2 level nested list as it, an object. it never knows it is a row x column, or maybe it is just a single level list. When you have 3 level or more, then which one should be considered column? Or how about combination of nested map/list? (example the way chrome bookmark is saved). So, we should be the one who tinkering around it to accomodate our need. When it is list or map, we iterate over it and work with it. From my scripting experience till know, as long as it is a properly formed list or map, we can always do something to rearrange it to our needs.

It is good to know there is alternative to make it easier.

For pause/wait, yes, it is sleep(). But for row/column can't be interchanged, as explained above. The quickest to be familiar with the script is (unfortunately) to use it many times. Before switching to Automagic, I learnt some python. So I have some problem when learning Automagic syntax. But as time went by (more than 1,5 years with Automagic), I never finish the python full tutorial. :D And until now, Automagic scripting still remain my strongest scripting language skill, above all other. It is because I use it more than anything else.

Example : When I need to copy some recent sent whatsapp image, I can finish the flow in a day (do it only on free time). But I still haven't finish my eventghost version (using python), so I can directly query the list using adb, no need to copy to temporary folder. In the end, I was stucked and lazy. I simply export the list path result from Automagic flow to a text file. Use eventghost to take that content and copy all the images from the path using adb. Much faster than I recreate it in eventghost. I have to run the flow first before copying, but still easier, because I haven't understand the concept of input dialog in python (while in Automagic, it is very easy).
Index of Automagic useful thread List of my other useful posts (and others')
Xiaomi Redmi Note 5 (whyred), AOSP Extended v6.7 build 20200310 Official, Android Pie 9.0, Rooted.

Post Reply