1

I'm trying to filter coordinates from 2 lists taken from a txt file by distance, I can't figure out what is going wrong with it since it is not deleting every coordinate that doesn't pass the if statement if distance is greater than 12 meters, delete item in list.

code:

x = [] # contains a list of x coordinates in EPGS: 2202
y = [] # contains a list of y coordinates in EPGS: 2202

keepItWorking = 0 # this is supposed to avoid offset once a coordinate is deleted.

xStore = x[0] # Stores x variable to evaluate distance and delete coordinates.
yStore = y[0] # Stores y variable to evaluate distance and delete coordinates.

def distance(x1, x2, y1, y2):
    return (math.sqrt(((x2 - x1)**2) + ((y2 - y1)**2)))

for i in range(1, len(x)):
    try:

        if distance(x[i - keepItWorking], xStore, y[i - keepItWorking], yStore) > 12 #if distance is greater than 12 store coordinates values and proceed to delete next coordinates with the new evaluation.
            xStore = x[i - keepItWorking]
            yStore = y[i - keepItWorking]

        elif distance(x[i - keepItWorking], xStore, y[i - keepItWorking], yStore) < 12 # if distance is lower than 12 meters delete values from list.
            del x[i - keepItWorking]
            del y[i - keepItWorking]
            keepItWorking = keepItWorking + 1

    except IndexError: # avoids error when index gets out of range becouse of the items eliminations.
        continue

Apparently I fixed the issue I was having while rewriting the code in here... It is working perfectly.

Thriskel
  • 351
  • 3
  • 13
  • Would you please share some data with us? – Anton vBR Sep 05 '17 at 15:33
  • 2
    Deleting elements from a list as you iterate by index is problematic. When you delete an element, all the indexes shift by 1. – Code-Apprentice Sep 05 '17 at 15:34
  • Does x[0] always correspond to y[0]? Why not store the coordinates as a list ordered pairs (tuples)? Code-Apprentice is right. I think using a list comprehension is your best bet. Can you share a sample list of points, which comparisons need to be made, and what you'd expect the filtered list to look like? – RagingRoosevelt Sep 05 '17 at 15:36
  • Possible duplicate of [Remove items from a list while iterating](https://stackoverflow.com/questions/1207406/remove-items-from-a-list-while-iterating) – SiHa Sep 05 '17 at 15:46
  • to avoid the shift issue the variable keepItWorking was created it is supposed to be 0 so when the distance calculated is less than 12 keepItWorking increases its value by 1 as the loop deletes 1 from list and that's why it is rested from every i value refering to an index. – Thriskel Sep 05 '17 at 15:55

3 Answers3

0

Deleting elements from a list as you iterate by index is problematic. When you delete an element, all the indexes shift by 1. I have two suggestions:

  1. Use a tuple to store your (x, y) pairs. This way you can keep a single list of pairs rather than two parallel lists.

  2. Use a list comprehension to filter your list. With a simple predicate function, you can reduce your entire code to one or two lines.

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
0

Here is an alternative way (might not be the most efficient but it works).

import numpy as np
import math

# Distance function
def calc_distance(tuple1,tuple2):
    return (math.sqrt(((tuple1[0]-tuple2[0])**2) + ((tuple1[1] - tuple2[1])**2)))

# Generate some random numbers
x = np.full(10, 2000)
y = np.append(2000,np.random.randint(8,16,size=9))
y = np.cumsum(y)
tuples = list(zip(x,y))

print(tuples) can look like this: [(2000, 2000), (2000, 2015), (2000, 2027), (2000, 2036), (2000, 2050), (2000, 2064), (2000, 2079), (2000, 2087), (2000, 2101), (2000, 2116)]

And print([calc_distance(i[0],i[1]) for i in list(zip(tuples,tuples[1:]))]): [15.0, 12.0, 9.0, 14.0, 14.0, 15.0, 8.0, 14.0, 15.0]

Now there might be a zillion more efficient codes but think about this: Let us set the distance to 0 and for every pair, e.g. ((2000, 2000), (2000, 2015)) we add the distance and store the index of that pair if distance is below 12. If it is larger than 12 we reset.

distance = 0
remove = []

for ind, pair in enumerate(list(zip(tuples,tuples[1:]))):

    distance+= calc_distance(pair[0],pair[1])

    if distance < 12:
        remove.append(ind+1) # +1 because we don't compare the first index in tuples.
    else:
        distance = 0

print(remove) now looks like this: [3,7]. Now we can finally create a new array with all the relevant tuples.

newtuples = []

for ind,i in enumerate(tuples):
    if ind not in remove:
        newtuples.append(i)

print(newtuples) looks like: [(2000, 2000), (2000, 2015), (2000, 2027), (2000, 2050), (2000, 2064), (2000, 2079), (2000, 2101), (2000, 2116)]

And print([calc_distance(i[0],i[1]) for i in list(zip(newtuples,newtuples[1:]))]) like this: [15.0, 12.0, 23.0, 14.0, 15.0, 22.0, 15.0]

Anton vBR
  • 18,287
  • 5
  • 40
  • 46
  • The point of this is to export every coordinate into a shapefile with separated fields that's why I was more comfortable dividing the lists, but you code definetly seems good – Thriskel Sep 05 '17 at 18:25
-2

You don't need to do most of the things you do. Just create a new filtered list and possibly a one-liner along the lines of this will do :

    x = [] # contains a list of x coordinates in EPGS: 2202
    y = [] # contains a list of y coordinates in EPGS: 2202

    def distance(x1, x2, y1, y2):
        return (math.sqrt(((x2 - x1)**2) + ((y2 - y1)**2)))

    filtered = [(coord_x, coord_y) for coord_x, coord_y a in zip(x, y) if distance(coord_x, x[0], coord_y, y[0]) > 12]

    filtered_x, filtered_y = zip(*filtered)

(not really tested - please treat this a pseudocode, corrections welcome)

Jarek.D
  • 1,274
  • 1
  • 8
  • 18