平Flatten不规则(任意嵌套)列表

558 投票
53 回答
210241 浏览
提问于 2025-04-15 18:37

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

不过据我所知,除了一个解决方案,其他的都无法处理像 [[[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

这是最好的方法吗?我有没有遗漏什么?有没有什么问题?

53 个回答

49

使用递归和鸭子类型的生成器(已更新为Python 3):

def flatten(L):
    for item in L:
        try:
            yield from flatten(item)
        except TypeError:
            yield item

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

我的解决方案:

import collections


def flatten(x):
    if isinstance(x, collections.Iterable):
        return [a for i in x for a in flatten(i)]
    else:
        return [x]

这个方法稍微简洁一点,但基本上是一样的。

477

使用生成器函数可以让你的代码更容易阅读,同时也能提高性能。

Python 2

在Python 2.6中,添加了Iterable ABC

from collections import Iterable

def flatten(xs):
    for x in xs:
        if isinstance(x, Iterable) and not isinstance(x, basestring):
            for item in flatten(x):
                yield item
        else:
            yield x

Python 3

在Python 3中,basestring不再使用了,但可以用元组 (str, bytes) 达到相同的效果。此外,yield from 操作符可以一次从生成器中返回一个项目。

from collections.abc import Iterable

def flatten(xs):
    for x in xs:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            yield from flatten(x)
        else:
            yield x

撰写回答