Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python 2 list comprehension and eval

How do you have a multiple line statement in either a list comprehension or eval?

I was trying to turn this code:

def f(x, y, b=''):
    for i in x:
        if i in y:
            y.remove(i)
            i *= 2
        b += i
    return b

Into a lambda function like so:

j=lambda x,y:''.join(eval('y.remove(i);i*2')if i in y else i for i in x)

In both x is a string such as 'onomatopoeia' and y is a list such as ['o','a','o'].

But for some reason, it returns a syntax error. Can anyone explain this?

like image 458
Beta Decay Avatar asked Jun 22 '15 17:06

Beta Decay


2 Answers

First, you probably shouldn't rewrite this with a lambda because of the side-effects in the loop. If you really want to anyway, don't use an eval.

I'd suggest:

j = lambda x, y: ''.join((y.remove(i) or 2 * i) if i in y else i for i in x)

Because the result of remove is None the second argument to or will be the result. This avoids the eval. But it's still worse then a for-loop.


As noted in comments on the original question, 2 * y.pop(y.index(i)) is more readable than the or construct. You'll loop twice over y, but performance doesn't seem the issue.

like image 164
Noctua Avatar answered Nov 09 '22 01:11

Noctua


I would vastly prefer your function but this will do what you want.

from itertools import chain
j = lambda x, y: ''.join(filter(None,chain.from_iterable((i * 2,y.remove(i)) if i in y else i for i in x)))

print(j("'onomatopoeia'",['o','a','o']))
'oonoomaatopoeia'
like image 40
Padraic Cunningham Avatar answered Nov 08 '22 23:11

Padraic Cunningham