S L
S L

Reputation: 14318

python - filter minimum element for given condition

From a list of tuple l, I need to filter the element which is at least euclidean distance from tuple x.

  1. Can I do this using list comprehension or lambda function? You can take l = [(0,0), (1,1), (2,3), (3,4), (4,5)] and x=(3,0).

  2. Suppose there are more than one elements in l whose euclidean distance is minimum at same time. Then I need to return random elements from those elements. Can this be done using list comprehension or lambda function too?

Upvotes: 3

Views: 4826

Answers (2)

tobias_k
tobias_k

Reputation: 82889

First you should define a function to get the Euclidian distance. One way would be to just convert the tuples to complex numbers and get their absolute difference.

>>> dist = lambda t1, t2: abs(complex(*t1) - complex(*t2))

Alternatively, you could define your own function. That might even be faster, since you do not really need to take the square root if you just want to find the value that has the minimum distance. You can then use that function as a key function to the min builtin.

>>> l = [(0,0), (1,1), (2,3), (3,4), (4,5)]
>>> x = (3,0)
>>> min(l, key = lambda y: dist(y, x))
(1, 1)

If you want to get all the minimum values, you could store that value in a variable and use a list comprehension to get all values whose distance is equal to that value.

>>> m = min(dist(y, x) for y in l)
>>> [y for y in l if dist(x, y) == m]
[(1, 1)]

If you want a random value of those, use random.choice:

>>> random.choice(_)
(1, 1)

Note, however, that this approach will iterate the list twice, and also calculate the distance of each value twice -- once to find the (any) minimum value, and then again to compare each value to that minimum. If performance is very important, you should use @Kasramvd's appraoch.

Upvotes: 3

Kasravnd
Kasravnd

Reputation: 107287

Here is an efficient approach using dictionary:

from operator import itemgetter
from random import choice

def find_mins(x, lst):
    x1, y1 = x
    result = {}
    for x2, y2 in lst:
        quad_dist = (x1 - x2)**2 + (y1 - y2)**2
        result.setdefault(quad_dist, []).append((x2, y2))
    return choice(min(result.items(), key=itemgetter(0))[1])

Demo :

l = [(0,0), (1,1), (2, 2), (2,3), (3,4), (4,5)]
x = (3,0)

find_mins(x, l)
(1, 1)
find_mins(x, l)
(2, 2)
find_mins(x, l)
(2, 2)

This function will categorize your coordinates based on their distance from intended point then find the minimum based on the distance and return the list of relative coordinates, then you can use random.choice() to pick up a random point.

Upvotes: 2

Related Questions