This question already has answers here:
Closed 8 years ago.
Possible Duplicates:
Making a flat list out of list of lists in Python
Flatten (an irregular) list of lists in Python
Input a list such as: [1,2,[3,4,[5,6,7,[8]]],[9],10]
Desired output: [1,2,3,4,5,6,7,8,9,10]
Currently I have the following recursive function:
def fix_list( li , l = [] ):
for i in li:
try:
len( i )
fix_list( i, l )
except:
l.append( i )
return l
I feel like the try/except catch is a little gimmicky and slow, and I'm wondering if there is a better/more optimized way to perform this task. All input is greatly appreciated.
Here is an iterative version (originally inspired by Artsiom Rudzenka's) that modifies the list in place using slice assignment rather than creating a new list on each pass. Interestingly, only one pass through the list is needed! My use of enumerate()
is a little unorthodox; I use it to keep track of an index into a list that may be growing as I iterate over it, but don't actually use the actual list item.
def flattened(items, seqtypes=(list, tuple)):
items = items[:] # we will return a copy; remove to mutate original
for i, _ in enumerate(items):
while isinstance(items[i], seqtypes):
items[i:i+1] = items[i]
return items
print flattened([1,2,[3,4,[5,6,7,[8]]],[9],10])
Generator version:
def flattener(items, seqtypes=(list, tuple)):
items = items[:]
for i, _ in enumerate(items):
while isinstance(items[i], seqtypes):
items[i:i+1] = items[i]
yield items[i]
print list(flattener([1,2,[3,4,[5,6,7,[8]]],[9],10]))
Here is a list
subclass that has a flatten()
method. Like the sort()
and reverse()
methods, this mutates the list and returns None
.
class listy(list):
def flatten(self, seqtypes=(list, tuple)):
for i, _ in enumerate(self):
while isinstance(self[i], seqtypes):
self[i:i+1] = self[i]
lst = listy([1,2,[3,4,[5,6,7,[8]]],[9],10])
lst.flatten()
print lst
Edit: I simplified this pretty significantly from my original version. However, I see the question has been closed.
See this answer:
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
Here's a simple generator that does this:
def flatten(nested):
for item in nested:
if isinstance(item, collections.Iterable) and not isinstance(item, basestring):
for inner_item in flatten(item):
yield inner_item
else:
yield item
Not sure whether it's "optimal" or not.
I have tried solution below and it works:
data = [1,2,[3,4,[5,6,7,[8]]],[9],10]
while any(isinstance(x, list) for x in data):
tmpLst = []
for x in data:
if isinstance(x, list):
tmpLst.extend(x)
else:
tmpLst.append(x)
data = tmpLst
Another approach ..
def flatten(old, new):
for i in old:
flatten(i, new) if isinstance(i, list) else new.append(i)
return new
if __name__ == '__main__':
l1 = [1, 2, [3, 4, [5, 6, 7, [8]]], [9], 10]
l2 = list()
l3 = flatten(l1, l2)
print l3
Simplified so you don't have to supply and empty list to the flatten argument list ..
def rec_flatten(old, new=list()):
for i in old:
rec_flatten(i, new) if isinstance(i, list) else new.append(i)
return new
if __name__ == '__main__':
l1 = [1, 2, [3, 4, [5, 6, 7, [8]]], [9], 10]
x = rec_flatten(l1)
print x