I have a list of vectors (in Python) that I want to normalize, while at the same time removing the vectors that originally had small norms.
The input list is, e.g.
a = [(1,1),(1,2),(2,2),(3,4)]
And I need the output to be (x*n, y*n)
with n = (x**2+y**2)**-0.5
If I just needed the norms, for example, that would be easy with a list comprehension:
an = [ (x**2+y**2)**0.5 for x,y in a ]
It would be also easy to store just a normalized x, too, for example, but what I want is to have this temporary variable "n", to use in two calculations, and then throw it away.
I can't just use a lambda function too because I also need the n to filter the list. So what is the best way?
Right now I am using this nested list comprehension here (with an expression in the inner list):
a = [(1,1),(1,2),(2,2),(3,4)]
[(x*n,y*n) for (n,x,y) in (( (x**2.+y**2.)**-0.5 ,x,y) for x,y in a) if n < 0.4]
# Out[14]:
# [(0.70710678118654757, 0.70710678118654757),
# (0.60000000000000009, 0.80000000000000004)]
The inner list generates tuples with an extra value (n), and then I use these values for the calculations and filtering. Is this really the best way? Are there any terrible inefficiencies I should be aware of?
You can't assign a variable in a comprehension, but you can use a nested generator expression, which does what I think you want (without a lambda function). Show activity on this post. You can't do that. Assignment is always a statement in Python; list comprehensions can only contain expressions.
1 Answer. Actually, list comprehension is much clearer and faster than filter+lambda, but you can use whichever you find easier.
Python list comprehension predicate. A predicate is a function that returns boolean value. If the condition is too complex, we can put it into a predicate. The example filters out all vowels from a sentence.
List comprehension offers a shorter syntax when you want to create a new list based on the values of an existing list. Example: Based on a list of fruits, you want a new list, containing only the fruits with the letter "a" in the name.
Is this really the best way?
Well, it does work efficiently and if you really, really want to write oneliners then it's the best you can do.
On the other hand, a simple 4 line function would do the same much clearer:
def normfilter(vecs, min_norm):
for x,y in vecs:
n = (x**2.+y**2.)**-0.5
if min_norm < n:
yield (x*n,y*n)
normalized = list(normfilter(vectors, 0.4))
Btw, there is a bug in your code or description - you say you filter out short vectors but your code does the opposite :p
Starting Python 3.8
, and the introduction of assignment expressions (PEP 572) (:=
operator), it's possible to use a local variable within a list comprehension in order to avoid calling multiple times the same expression:
In our case, we can name the evaluation of (x**2.+y**2.)**-.5
as a variable n
while using the result of the expression to filter the list if n
is inferior than 0.4
; and thus re-use n
to produce the mapped value:
# vectors = [(1, 1), (1, 2), (2, 2), (3, 4)]
[(x*n, y*n) for x, y in vectors if (n := (x**2.+y**2.)**-.5) < .4]
# [(0.7071067811865476, 0.7071067811865476), (0.6000000000000001, 0.8)]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With