开发者

How to optimally turn a multidimentional list into a single list of items in Python? [duplicate]

This question already has answers here: Closed 11 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 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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜