如何以最快的方式在Python中展平任意嵌套列表?

2024-05-23 13:51:43 发布

您现在位置:Python中文网/ 问答频道 /正文

Possible Duplicate:
Flattening a shallow list in Python
Flatten (an irregular) list of lists in Python

编辑:问题不是如何做到这一点-这一直是discussed在另一个questions-问题是,哪一个是最快的方法?

我以前找到过解决方案,但我想知道最快的解决方案是将包含任意长度的其他列表的列表展平。

例如:

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

会变成:

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

可以有无限多个层次。有些列表对象可以是字符串,但不能在输出列表中将其展平为连续字符。


Tags: ofinan编辑列表解决方案listslist
3条回答

下面是一个对字符串友好的递归方法:

nests = [1, 2, [3, 4, [5],['hi']], [6, [[[7, 'hello']]]]]

def flatten(container):
    for i in container:
        if isinstance(i, (list,tuple)):
            for j in flatten(i):
                yield j
        else:
            yield i

print list(flatten(nests))

返回:

[1, 2, 3, 4, 5, 'hi', 6, 7, 'hello']

注意,这并不能保证速度和开销的使用,但是说明了一个递归的解决方案,希望它会有帮助。

它不具有递归性。事实上,由于函数调用所涉及的开销,迭代解决方案通常更快。这是我不久前写的一个迭代版本:

def flatten(items, seqtypes=(list, tuple)):
    for i, x in enumerate(items):
        while i < len(items) and isinstance(items[i], seqtypes):
            items[i:i+1] = items[i]
    return items

还没有测试过这个特定实现的性能,但它可能没有那么好,因为所有的片分配,最终可能会移动大量内存。不过,不要假设它必须是递归的,或者这样写会更简单。

这种实现的优点是“就地”展平列表,而不是像递归解决方案一样返回副本。当内存不足时,这可能很有用。如果需要展开副本,只需传入要展开的列表的浅副本:

flatten(mylist)                # flattens existing list
newlist = flatten(mylist[:])   # makes a flattened copy

此外,该算法不受Python递归限制,因为它不是递归的。不过,我敢肯定这几乎永远不会起作用。

此函数应能够在不使用任何递归的情况下快速展平嵌套的可iterable容器:

import collections

def flatten(iterable):
    iterator = iter(iterable)
    array, stack = collections.deque(), collections.deque()
    while True:
        try:
            value = next(iterator)
        except StopIteration:
            if not stack:
                return tuple(array)
            iterator = stack.pop()
        else:
            if not isinstance(value, str) \
               and isinstance(value, collections.Iterable):
                stack.append(iterator)
                iterator = iter(value)
            else:
                array.append(value)

大约五年后,我对这件事的看法发生了变化,这也许更适合用:

def main():
    data = [1, 2, [3, 4, [5], []], [6]]
    print(list(flatten(data)))


def flatten(iterable):
    iterator, sentinel, stack = iter(iterable), object(), []
    while True:
        value = next(iterator, sentinel)
        if value is sentinel:
            if not stack:
                break
            iterator = stack.pop()
        elif isinstance(value, str):
            yield value
        else:
            try:
                new_iterator = iter(value)
            except TypeError:
                yield value
            else:
                stack.append(iterator)
                iterator = new_iterator


if __name__ == '__main__':
    main()

相关问题 更多 >