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 thi开发者_运维问答s 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
精彩评论