是的,我知道这个主题之前已经被讨论过了:

Python成语链(扁平化)有限迭代对象的无限迭代? 在Python中扁平化一个浅列表 理解平展一个序列的序列吗? 我如何从列表的列表中创建一个平面列表?

但据我所知,所有的解决方案,除了一个,在像[[[1,2,3],[4,5]],6]这样的列表上失败,其中期望的输出是[1,2,3,4,5,6](或者更好,一个迭代器)。

我看到的唯一解决方案,适用于任意嵌套是在这个问题:

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

这是最好的方法吗?我是不是忽略了什么?任何问题吗?


当前回答

这个答案的一个更有效的版本是:https://stackoverflow.com/a/20495215/8887313

如果您可以控制列表的创建并愿意更改它,那么使用deque(而不是pop(0)和列表contatenation)会更有效。

import collections

def flatten_and_consume(nested_deque: collections.deque):
    while nested_deque:
        elt = nested_deque.popleft()

        elt_is_sublist = isinstance(elt, collections.deque)
        if elt_is_sublist:
            nested_deque.extendleft(reversed(elt))
        else:
            yield elt

其他回答

我是python的新手,有lisp的背景。这是我想出的(检查lulz的var名称):

def flatten(lst):
    if lst:
        car,*cdr=lst
        if isinstance(car,(list,tuple)):
            if cdr: return flatten(car) + flatten(cdr)
            return flatten(car)
        if cdr: return [car] + flatten(cdr)
        return [car]

似乎有用。测试:

flatten((1,2,3,(4,5,6,(7,8,(((1,2)))))))

返回:

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

我不确定这是否更快或更有效,但这就是我所做的:

def flatten(lst):
    return eval('[' + str(lst).replace('[', '').replace(']', '') + ']')

L = [[[1, 2, 3], [4, 5]], 6]
print(flatten(L))

这里的flatten函数将列表转换为一个字符串,去掉所有的方括号,将方括号附加到末尾,并将其转换为列表。

但是,如果你知道你的列表中会有方括号,比如[[1,2],"[3,4]和[5]"],你就必须做一些其他的事情。

虽然已经选择了一个优雅和非常python的答案,但我将提出我的解决方案,只是为了回顾:

def flat(l):
    ret = []
    for i in l:
        if isinstance(i, list) or isinstance(i, tuple):
            ret.extend(flat(i))
        else:
            ret.append(i)
    return ret

请告诉我这个代码是好是坏?

def nested_list(depth):
    l = [depth]
    for i in range(depth-1, 0, -1):
        l = [i, l]
    return l

nested_list(10)

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

def Flatten(ul):
    fl = []
    for i in ul:
        if type(i) is list:
            fl += Flatten(i)
        else:
            fl += [i]
    return fl

Flatten(nested_list(10))

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

基准测试

l = nested_list(100)

https://stackoverflow.com/a/2158532

import collections

def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
            yield from flatten(el)
        else:
            yield el
%%timeit -n 1000
list(flatten(l))

320µs±14.3µs / loop(平均±std. dev. 7次运行,每个循环1000次)

%%timeit -n 1000
Flatten(l)

60µs±10.2µs / loop(平均±std. dev. 7次运行,每个循环1000次)

list(flatten(l)) == Flatten(l)

真正的

从我之前的回答来看,这个函数使我能想到的大多数情况变得平坦。我相信这适用于python 2.3。

def flatten(item, keepcls=(), keepobj=()):
    if not hasattr(item, '__iter__') or isinstance(item, keepcls) or item in keepobj:
        yield item
    else:
        for i in item:
            for j in flatten(i, keepcls, keepobj + (item,)):
                yield j

循环链表

>>> list(flatten([1, 2, [...], 3]))
[1, 2, [1, 2, [...], 3], 3]

深度优先列表

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

嵌套重复列表:

>>> list(flatten([[1,2],[1,[1,2]],[1,2]]))
[1, 2, 1, 1, 2, 1, 2]

带有字典的列表(或其他不要压平的对象)

>>> list(flatten([1,2, {'a':1, 'b':2}, 'text'], keepcls=(dict, str)))
[1, 2, {'a': 1, 'b': 2}, 'text']

任何iterable

>>> list(flatten((x for x in [1,2, set([3,(4,5),6])])))
[1, 2, 4, 5, 3, 6]

您可能希望在keepcls中保留一些默认类来进行调用 函数更简洁。