Double Iteration in List Comprehension
Here’s something I didn’t know possible in Python: iteration over more than one iterable in a list comprehension:
>>> seq_x = [1, 2, 3, 4]
>>> seq_y = 'abc'
>>> [(x,y) for x in seq_x for y in seq_y]
[(1, 'a'),
(1, 'b'),
(1, 'c'),
(2, 'a'),
(2, 'b'),
(2, 'c'),
(3, 'a'),
(3, 'b'),
(3, 'c'),
(4, 'a'),
(4, 'b'),
(4, 'c')]
Cool, isn’t it? It’s equivalent to the following snippet:
>>> result = []
... for x in seq_x:
... for y in seq_y:
... result.append((x,y))
>>> result
[(1, 'a'),
(1, 'b'),
(1, 'c'),
(2, 'a'),
(2, 'b'),
(2, 'c'),
(3, 'a'),
(3, 'b'),
(3, 'c'),
(4, 'a'),
(4, 'b'),
(4, 'c')]
It also supports both “if” statements and referencing the outer iterator from the inner one, like so:
>>> seq = ['abc', 'def', 'g', 'hi']
... [y for x in seq if len(seq) > 1 for y in x if y != 'e']
['a', 'b', 'c', 'd', 'f', 'g', 'h', 'i']
This is equivalent to the snippet:
>>> result = []
... for x in seq:
... if len(seq) > 1:
... for y in x:
... if y != 'e':
... result.append(y)
... result ['a', 'b', 'c', 'd', 'f', 'g', 'h', 'i']
The thing you should notice here, is that the outer loop is the first ‘for’ loop in the list comprehension. This was a little confusing for me at first because when I nest list comprehensions it’s the other way around.
To read more about this feature, check out this StackOverflow thread or the Python Manual.