Elegant summation of list comprehension

Viewed 75

List comprehensions are great. Is there an elegant, slick way to do a list comprehension that appends items to each other as they go, rather than putting them all in a list?

IE, I have some comprehension [func(x) for x in y if z] that spits out [['a','b'],['c','d'],['e','f']], what can i write to instead spit out ['a','b','c','d','e','f']?

Obviously I could do

alist = []

for x in y:
    if z:
        alist += func(x)

but that's four or five lines of code! it feels like there must be a way to do it that's as simple and easy as the list comprehension is.

2 Answers
[elem for x in y if z for elem in func(x)]

Just add another layer of iteration.

This question isn't specific to list comprehensions; it has to do with flattening of nested containers or iterables in general. (That would include, list, tuple, set, etc.)

Unlike some sloppier programming languages — cough whose names also start with “P” cough — Python never implicitly flattens nested containers.

The standard-library Pythonic way to flatten a nested container is with itertools.chain, which works as a generator and thus avoids making unnecessary intermediary copies of the list, or whatever iterable you pass it. There are two ways to invoke it:

  • chain(iterable1, iterable2, …): for example, list(chain([1,2],[3,4])) → [1, 2, 3, 4]
  • chain.from_iterable(iterable_of_iterables): for example, l = [[1, 2], [3, 4]]; list(chain.from_iterable(l)) → [1, 2, 3, 4]

For your specific example:

from itertools import chain

# Your starting case:
l = [['a','b'],['c','d'],['e','f']]

# This is now an iterator, not a list
it = chain.from_iterable(l)

# Make it back into a list
l2 = list(it)

# Prints:
#   ['a', 'b', 'c', 'd', 'e', 'f']
print(l2)
Related