Reputation: 9649
FP like Haskell can bind a (var) name trivially e.g:
[(g y, h y) | x <- mylist, let y = f x]
Python does it possibly below:
mylist = [f(x) for x in mylist]
mylist = [(g(y), h(y)) for y in mylist]
Walrus assignment in Python 3.8 seems a hack to simplify list comprehensions :
[(y := f(x), g(y), h(y)) for x in mylist]
What is so far considered pythonic way in this case?
Upvotes: 2
Views: 182
Reputation: 652
Some other questions are linked here (such as python how to declare variable in for comprehension without iterating) so let me answer a slightly more general question.
How to bind a local variable within a for
comprehension without iteration. The trick is to create a singleton list and iterate over it such as for b in [u(a)]
in the following.
One might find this ugly and cryptic, but it is the most concise way I have found.
[x for a in f(x) for b in [u(a)] if v(b) for x in w(b)]
Upvotes: 0
Reputation: 51034
Since Python doesn't have "let ... in ..." expressions, the cleanest way is to write a function and call it.
def apply_g_h(x):
y = f(x)
return g(y), h(y)
mylist = [ apply_g_h(x) for x in mylist ]
If you really prefer it as a one-liner, then a lambda function can serve the same purpose:
mylist = [ (lambda y: (g(y), h(y)))(f(x)) for x in mylist ]
This works because a "let" expression let x = e1 in e2
is equivalent to (lambda x: e2)(e1)
. I've had to do this occasionally when limited to only writing expressions (to be passed to eval
), but it's not very readable, so I think the first solution is much better.
Upvotes: 1
Reputation: 531055
The correct use of the walrus operator to create 2-tuples would be
mylist = [(g(y:=f(x)), h(y)) for x in mylist]
which, yes, is even more horrendous than the 3-tuple version. If you want to forgo the walrus operator, use the version which :=
was supposed to obviate:
mylist = [(g(y), h(y)) for x in mylist for y in [f(x)]]
or more simply
mylist = [(g(y), h(y)) for y in map(f, mylist)]
I would not say the walrus operator is always so ungainly, but it seems to be more trouble than it is worth here.
Upvotes: 7
Reputation: 724
I would argue that map
is more appropriate for applying an operation on every element of a list.
mylist = map(f, mylist)
mylist = list(map(lambda x: (g(x), g(x)), mylist))
Upvotes: 1