No, Daniel, I don’t know a better way ATM.
A possible reason for this obvious lack could be that the Python community likes to have functions with clear semantics. For example, sometimes I want to flatten only one level, or different types, for example, given this input:

@Will: Daniels version looks more optimized to me. The question whether isinstance is better than checking the class is another possible implementation decision, e.g. given the following definition of MyVector:

class MyVector(list):
def __init__(self, *args):
list.__init__(self, args)

Your version would handle it the same as a list, while daniels would not flatten it.

For the record, the above corresponds to the following checks in Daniel’s flatten function:
if i.__class__ is list:
if i.__class__ in (list, tuple):
if isinstance(i, list):
if isinstance(i, (list, tuple)):
if hasattr(i, “__iter__”):
AFAICS the simplest way to flatten only one layer is to change the recursive call to “list” instead of “flatten”.

import sys
def flatten(inlist, ltype=(list,tuple), maxint=sys.maxint):
try:
for ind in xrange(maxint):
while isinstance(inlist[ind], ltype):
inlist[ind:ind+1] = list(inlist[ind])
except IndexError:
pass
return inlist

sweavosays:

def flatten(l):
if isinstance(l,list):
return sum(map(flatten,l))
else:
return l

anonsays:

def flatten(x):
result = []
for v in x:
if hasattr(v, ‘__iter__’) and not isinstance(v, basestring):
result.extend(flatten(v))
else:
result.append(v)
return result

BioStatMattsays:

As far as I can tell, several of the functions presented above do not work, including sweavo’s. Thie function below does work.

def flatten(x):
ans = []
for i in range(len(x)):
if isinstance(x[i],list):
ans = x[:i]+flatten(x[i])+x[i+1:]
else:
ans.append(x[i])
return ans

BioStatMattsays:

Sorry, my previous post didn’t work either. But this one does. Honest.

def flatten(x):
ans = []
for i in range(len(x)):
if isinstance(x[i],list):
ans.extend(flatten(x[i]))
else:
ans.append(x[i])
return ans

timvsays:

A modified version of sweavo’s post (which didn’t work for me either):

def flatten(l):
if isinstance(l,list):
return sum(map(flatten,l),[])
else:
return [l]

Markussays:

What about using the reduce-function?

E.g.

def flatten(l):
return reduce(operator.add, l)

Obviously this requires the operator-module import.

Bob the Chefsays:

There is a problem with most of these in that they’re recursive. Why is it a problem? Because python’s stack is going to blow up when the depth of the list is something ridiculously large.

So, we must do this with iteration. One way is to iterate over the list until no lists remain:

def flatten(lst):
has_lists = True
while has_lists:
tmp_lst = []
has_lists = False
for elt in lst:
if isinstance(elt, list):
tmp_lst += elt
has_lists = True
else:
tmp_lst.append(elt)
lst = tmp_lst
return lst

Of course, you’re doing more iteration that you need to if the list contains elements of variable list depth. But since function calls are expensive in Python, it may actually be faster than recursion.

grimborgsays:

works with recursive arrays too… maybe a bit too long though

def flatten(inlist):
res = []
def append(l):
try: res.extend(flatten(l))
except TypeError:res.append(l)
map(append, inlist)
return res

Willsays:I think you just want isinstance, but here’s a nice recursive function:

How about:

def flatten(x):

if not isinstance(x,list):

return x

elif len(x) is 0:

return []

elif isinstance(x[0],list):

return flatten(x[0]) + flatten(x[1:])

else:

return [x[0]] + flatten(x[1:])

Hans Meinesays:No, Daniel, I don’t know a better way ATM.

A possible reason for this obvious lack could be that the Python community likes to have functions with clear semantics. For example, sometimes I want to flatten only one level, or different types, for example, given this input:

[[[1,2,3], (42,None)], [4,5], [6], 7, MyVector(8,9,10)]

One could imagine the following outputs:

# flattened one level:

[[1, 2, 3], (42, None), 4, 5, 6, 7, MyVector(8,9,10)]

# flattened all lists:

[1, 2, 3, (42, None), 4, 5, 6, 7, MyVector(8,9,10)]

# flattened all lists and tuples:

[1, 2, 3, 42, None, 4, 5, 6, 7, MyVector(8,9,10)]

# flattened all iterables:

[1, 2, 3, 42, None, 4, 5, 6, 7, 8, 9, 10]

@Will: Daniels version looks more optimized to me. The question whether isinstance is better than checking the class is another possible implementation decision, e.g. given the following definition of MyVector:

class MyVector(list):

def __init__(self, *args):

list.__init__(self, args)

Your version would handle it the same as a list, while daniels would not flatten it.

For the record, the above corresponds to the following checks in Daniel’s flatten function:

if i.__class__ is list:

if i.__class__ in (list, tuple):

if isinstance(i, list):

if isinstance(i, (list, tuple)):

if hasattr(i, “__iter__”):

AFAICS the simplest way to flatten only one layer is to change the recursive call to “list” instead of “flatten”.

Jordan Callicoatsays:Here is a version from the mailing list:

`def flatten(seq):`

res = []

for item in seq:

if (isinstance(item, (tuple, list))):

res.extend(flatten(item))

else:

res.append(item)

return res

Another version is listed a in recipe 363051:

`import sys`

def flatten(inlist, ltype=(list,tuple), maxint=sys.maxint):

try:

for ind in xrange(maxint):

while isinstance(inlist[ind], ltype):

inlist[ind:ind+1] = list(inlist[ind])

except IndexError:

pass

return inlist

sweavosays:def flatten(l):

if isinstance(l,list):

return sum(map(flatten,l))

else:

return l

anonsays:def flatten(x):

result = []

for v in x:

if hasattr(v, ‘__iter__’) and not isinstance(v, basestring):

result.extend(flatten(v))

else:

result.append(v)

return result

BioStatMattsays:As far as I can tell, several of the functions presented above do not work, including sweavo’s. Thie function below does work.

def flatten(x):

ans = []

for i in range(len(x)):

if isinstance(x[i],list):

ans = x[:i]+flatten(x[i])+x[i+1:]

else:

ans.append(x[i])

return ans

BioStatMattsays:Sorry, my previous post didn’t work either. But this one does. Honest.

def flatten(x):

ans = []

for i in range(len(x)):

if isinstance(x[i],list):

ans.extend(flatten(x[i]))

else:

ans.append(x[i])

return ans

timvsays:A modified version of sweavo’s post (which didn’t work for me either):

def flatten(l):

if isinstance(l,list):

return sum(map(flatten,l),[])

else:

return [l]

Markussays:What about using the reduce-function?

E.g.

def flatten(l):

return reduce(operator.add, l)

Obviously this requires the operator-module import.

Bob the Chefsays:There is a problem with most of these in that they’re recursive. Why is it a problem? Because python’s stack is going to blow up when the depth of the list is something ridiculously large.

So, we must do this with iteration. One way is to iterate over the list until no lists remain:

def flatten(lst):

has_lists = True

while has_lists:

tmp_lst = []

has_lists = False

for elt in lst:

if isinstance(elt, list):

tmp_lst += elt

has_lists = True

else:

tmp_lst.append(elt)

lst = tmp_lst

return lst

Of course, you’re doing more iteration that you need to if the list contains elements of variable list depth. But since function calls are expensive in Python, it may actually be faster than recursion.

grimborgsays:works with recursive arrays too… maybe a bit too long though

def flatten(inlist):

res = []

def append(l):

try: res.extend(flatten(l))

except TypeError:res.append(l)

map(append, inlist)

return res

Test:

>>> print flatten([[[[1]]],[2],[[[3],4,5],6],7])

[1,2,3,4,5,6,7]

grimborgsays:ahh spaces got cut.

def flatten(inlist):

____ res = []

____ def append(l):

________ try: res.extend(flatten(l))

________ except TypeError:res.append(l)

____ map(append, inlist)

____ return res

Ionel Mariessays:reduce(lambda a, b: isinstance(b, (list, tuple)) and a+list(b) or a.append(b) or a, the_nested_list, [])

Johnsays:If you don’t mind losing the order of the list, you can do it with a nonrecursive oneliner;

lambda X:(lambda x:filter(lambda x:not hasattr(x,’__iter__’),[[x.append(j) for j in i] if hasattr(i,’__iter__’) else i for i in x]))(list(X))

Luchosays:>>> def flatten(l):

… return reduce(lambda a,b: a + (flatten(b) if hasattr(b, ‘__iter__’) else [b]), l, [])

…

>>> flatten([1,[2,3,[4,[5,6],7],8,[9,10,[11]]]])

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

Gabrielsays:def flatten(lst):

for el in lst:

if hasattr(el, “__iter__”) and not isinstance(el, basestring):

for x in flatten(el):

yield x

else:

yield el

krononetsays:def flatten(aList):

copyL = []

for k in aList:

if type(k) == type([]):

copyL = copyL + flatten(k)

else:

copyL.append(k)

return copyL