This question already has an answer here:
Is there a simple way to flatten a list of iterables with a list comprehension, or failing that, what would you all consider to be the best way to flatten a shallow list like this, balancing performance and readability?
I tried to flatten such a list with a nested list comprehension, like this:
[image for image in menuitem for menuitem in list_of_menuitems]
But I get in trouble of the NameError
variety there, because the name 'menuitem' is not defined
. After googling and looking around on Stack Overflow, I got the desired results with a reduce
statement:
reduce(list.__add__, map(lambda x: list(x), list_of_menuitems))
But this method is fairly unreadable because I need that list(x)
call there because x is a Django QuerySet
object.
Conclusion:
Thanks to everyone who contributed to this question. Here is a summary of what I learned. I'm also making this a community wiki in case others want to add to or correct these observations.
My original reduce statement is redundant and is better written this way:
>>> reduce(list.__add__, (list(mi) for mi in list_of_menuitems))
This is the correct syntax for a nested list comprehension (Brilliant summary dF!):
>>> [image for mi in list_of_menuitems for image in mi]
But neither of these methods are as efficient as using itertools.chain
:
>>> from itertools import chain
>>> list(chain(*list_of_menuitems))
And as @cdleary notes, it's probably better style to avoid * operator magic by using chain.from_iterable
like so:
>>> chain = itertools.chain.from_iterable([[1,2],[3],[5,89],[],[6]])
>>> print(list(chain))
>>> [1, 2, 3, 5, 89, 6]
In Python 2.6, using
chain.from_iterable()
:It avoids creating of intermediate list.
If you have to flat more complicated list with not iterable elements or with depth more than 2 you can use following function:
It will return generator object which you can convert to list with
list()
function. Notice thatyield from
syntax available from python3.3 but you can use explicit iteration instead.Example:
The easiest way to achieve this in either Python 2 or 3 is to use the morph library using
pip install morph
.The code is:
This version is a generator.Tweak it if you want a list.
You can add a predicate ,if want to flatten those which satisfy a condition
Taken from python cookbook
Here is a version working for multiple levels of list using
collectons.Iterable
: