Question

I like to use the following idiom for combining lists together, sometimes:

>>> list(itertools.chain(*[[(e, n) for e in l] for n, l in (('a', [1,2]),('b',[3,4]))]))
[(1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]

(I know there are easier ways to get this particular result, but it comes comes in handy when you want to iterate over the elements in lists of lists of lists, or something like that. The trouble is, when you use generator expressions, this becomes error prone. E.g.

>>> list(itertools.chain(*(((e, n) for e in l) for n, l in (('a', [1,2]),('b',[3,4])))))
[(1, 'b'), (2, 'b'), (3, 'b'), (4, 'b')]

What's happening here is that the inner generator expressions get passed as arguments to itertools.chain, so at the the time they're evaluated, the outer generator expression has finished, and n is fixed at its final value, 'b'. I'm wondering whether anyone has thought of ways to avoid this kind of error, beyond "don't do that."

Was it helpful?

Solution

Your approach almost works, you just need to flatten the generators. See how the for e in l is moved to the very right

>>> list(itertools.chain((e, n) for n, l in (('a', [1,2]),('b',[3,4])) for e in l ))
[(1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]

Here is how to do the same thing using itertools.product

>>> X=itertools.chain(*(itertools.product(*i[::-1]) for i in (('a', [1,2]),('b',[3,4]))))
>>> print list(X)
[(1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]

or if you are allowed to switch the tuples around

>>> X=itertools.chain(*(itertools.product(*i) for i in (([1,2],'a'),([3,4],'b'))))
>>> print list(X)
[(1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]

OTHER TIPS

wouldn't a nested list comprehension be more appropriate?

>>> tt = (('a', [1,2]),('b',[3,4]))
>>> [(s, i) for i, l in tt for s in l]
[(1, 'a'), (2, 'a'), (3, 'b'), (4, 'b')]

I'm going to suggest

data = (('a', [1,2]), ('b', [3,4]))

result = []
for letter, numbers in data:
     for number in numbers:
         result.append((number, letter))

It's a lot more readable than your solution family. Fancy is not a good thing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top