Snippets

Sergey Prymak flatten list of lists

Created by Sergey Prymak
recipients = list(itertools.chain.from_iterable(map(operator.attrgetter('to'), mail.outbox)))
recipients = [item for sublist in map(operator.attrgetter('to'), mail.outbox) for item in sublist]
recipients = sum(map(operator.attrgetter('to'), mail.outbox), [])
recipients = reduce(operator.add, map(operator.attrgetter('to'), mail.outbox))

[leaf for tree in forest for leaf in tree]

python -mtimeit -s'from itertools import chain; l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'list(chain.from_iterable(l))'
10000 loops, best of 3: 32.7 usec per loop
python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 60.8 usec per loop
python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(l, [])'
1000 loops, best of 3: 477 usec per loop
python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'import operator' 'reduce(operator.add,l)'
1000 loops, best of 3: 498 usec per loop
python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,l)'
1000 loops, best of 3: 514 usec per loop

Explanation: the shortcuts based on + (including the implied use in sum) are, of necessity, O(L**2) when there are L sublists -- as the intermediate result list keeps getting longer, at each step a new intermediate result list object gets allocated, and all the items in the previous intermediate result must be copied over (as well as a few new ones added at the end). So (for simplicity and without actual loss of generality) say you have L sublists of I items each: the first I items are copied back and forth L-1 times, the second I items L-2 times, and so on; total number of copies is I times the sum of x for x from 1 to L excluded, i.e., I * (L**2)/2.

The list comprehension just generates one list, once, and copies each item over (from its original place of residence to the result list) also exactly once.

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.