Flatten an irregular list of lists
Yes, I know this subject has been covered before (here, here, here, here), but as far as I know, all solutions, except for one, fail on a list like this:
L = [[[1, 2, 3], [4, 5]], 6]
Where the desired output is
[1, 2, 3, 4, 5, 6]
Or perhaps even better, an iterator. The only solution I saw that works for an arbitrary nesting is found in this question:
def flatten(x):
result = []
for el in x:
if hasattr(el, "__iter__") and not isinstance(el, basestring):
result.extend(flatten(el))
else:
result.append(el)
return result
flatten(L)
Is this the best model? Did I overlook something? Any problems?
Solution 1:
Using generator functions can make your example a little easier to read and probably boost the performance.
Python 2
def flatten(l):
for el in l:
if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
for sub in flatten(el):
yield sub
else:
yield el
I used the Iterable ABC added in 2.6.
Python 3
In Python 3, the basestring
is no more, but you can use a tuple of str
and bytes
to get the same effect there.
The yield from
operator returns an item from a generator one at a time. This syntax for delegating to a subgenerator was added in 3.3
from collections.abc import Iterable
def flatten(l):
for el in l:
if isinstance(el, Iterable) and not isinstance(el, (str, bytes)):
yield from flatten(el)
else:
yield el
Solution 2:
My solution:
import collections
def flatten(x):
if isinstance(x, collections.Iterable):
return [a for i in x for a in flatten(i)]
else:
return [x]
A little more concise, but pretty much the same.
Solution 3:
Generator using recursion and duck typing (updated for Python 3):
def flatten(L):
for item in L:
try:
yield from flatten(item)
except TypeError:
yield item
list(flatten([[[1, 2, 3], [4, 5]], 6]))
>>>[1, 2, 3, 4, 5, 6]