是的我知道该主题已覆盖之前 (这里这里这里这里),但据我所知,所有的解决方案,除了一个,如下列表上的失败︰

L = [[[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

flatten(L)

这是最佳的模型吗?我忽略一些吗?任何有问题吗?

2010-01-28 22:15:42
问题评论:

有这么多答案和这么多行动,关于这个问题的事实确实表明,这应该是内置函数的地方,对吗?它的特别遗憾的是 compiler.ast 移除了从 Python 3.0

我想说,Python 的真正需要是连续的递归而不是另一个内建的。

回答:

使用生成器功能可以使您的示例更容易地阅读,并可能提高性能。

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

我使用在 2.6 中添加Iterable ABC

在 Python 3, basestring是不会有,但您可以使用

basestring = (str, bytes)

若要获取那里相同的效果。

我喜欢,这是一台发电机,和非常清楚。添加防止出现在列表中有一个字符串 (不在原始的说明书中,但将明确熔断的递归限制),会使完美。

你是对的。我添加了一个字符串检查。

在此页上的所有建议,这都是拼合此列表的唯一一个l = ([[chr(i),chr(i-32)] for i in xrange(ord('a'), ord('z')+1)] + range(0,9))在何时我该list(flatten(l))管理单元中。所有其他成员,会开始使用时,请永远 !

可以进一步简化而不该循环使用yield from flatten(el) python3.3 + 中。

这还会拼合词典。也许您想要使用collections.Sequence而不是collections.Iteratable?

只可以在compiler.ast模块中使用平整成形函数。

>>> from compiler.ast import flatten
>>> flatten([0, [1, 2], [3, 4, [5, 6]], 7])
[0, 1, 2, 3, 4, 5, 6, 7]

很好,但这是否记录了任何地方?我找不到任何编译器页上。

只是警告该编译器的公正已被否决。

compiler将 Python 3 中删除。

实现本质上是相同 Cristian 的答案,尽管限于tuplelist类型。

生成器版本的 @unutbu 的非递归解决方案,在注释中的 @Andrew 的要求︰

def genflat(l, ltypes=collections.Sequence):
    l = list(l)
    i = 0
    while i < len(l):
        while isinstance(l[i], ltypes):
            if not l[i]:
                l.pop(i)
                i -= 1
                break
            else:
                l[i:i + 1] = l[i]
        yield l[i]
        i += 1

此生成器稍微简化的版本︰

def genflat(l, ltypes=collections.Sequence):
    l = list(l)
    while l:
        while l and isinstance(l[0], ltypes):
            l[0:1] = l[0]
        if l: yield l.pop(0)

它是由嵌套列表构成树的前序遍历。返回只是树叶。请注意,此实现将消耗原始数据结构,为更好或更糟。可能是有趣编写一个既保留原来的树中,但也没有要复制的列表项。

我认为您需要测试的字符串,如添加"并没有 isinstance (basestring l [0])"如 Cristian 的解决方案。否则可能会无限循环周围 l [0:1] = l [0]

这是一个很好的示例,创建一个生成器,但作为 c urchin 提及的算法本身失败时序列中不包含字符串。

我的解决方案︰

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

更简洁,但非常相似。

import collections是必需的但它工作正常的[[[1, 2, 3], [4, 5]], 6]

您可以这样做而不导入任何东西如果您只try: iter(x)测试是否 iterable...但是,我认为无需导入 stdlib 模块是值得避免不利因素。

值得注意的是,此方法才有效只有int类型的所有项

此版本的flatten可以避免 python 的递归限制 (并因此适用于任意深度的、 嵌套的 iterables)。它是一个生成器,它可以处理字符串和任意 iterables (甚至无限链接)。

import itertools as IT
import collections

def flatten(iterable, ltypes=collections.Iterable):
    remainder = iter(iterable)
    while True:
        first = next(remainder)
        if isinstance(first, ltypes) and not isinstance(first, basestring):
            remainder = IT.chain(first, remainder)
        else:
            yield first

下面是一些示例来演示其用法︰

print(list(IT.islice(flatten(IT.repeat(1)),10)))
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

print(list(IT.islice(flatten(IT.chain(IT.repeat(2,3),
                                       {10,20,30},
                                       'foo bar'.split(),
                                       IT.repeat(1),)),10)))
# [2, 2, 2, 10, 20, 30, 'foo', 'bar', 1, 1]

print(list(flatten([[1,2,[3,4]]])))
# [1, 2, 3, 4]

seq = ([[chr(i),chr(i-32)] for i in xrange(ord('a'), ord('z')+1)] + range(0,9))
print(list(flatten(seq)))
# ['a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G', 'h', 'H',
# 'i', 'I', 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N', 'o', 'O', 'p', 'P',
# 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T', 'u', 'U', 'v', 'V', 'w', 'W', 'x', 'X',
# 'y', 'Y', 'z', 'Z', 0, 1, 2, 3, 4, 5, 6, 7, 8]

尽管flatten可以处理无限生成器,它可以处理无限嵌套︰

def infinitely_nested():
    while True:
        yield IT.chain(infinitely_nested(), IT.repeat(1))

print(list(IT.islice(flatten(infinitely_nested()), 10)))
# hangs

因此,最佳答案应以某种方式使这一台发电机。

在使用 ABC Iterable 还是 ABC 序列上任何共识?

setsdictsdequeslistiteratorsgenerators、 filehandles 和__iter__定义具有自定义类的所有实例的collections.Iterable,但不是collections.Sequence拼合dict的结果是有点这个,可是,否则,我觉得collections.Iterablecollections.Sequence无疑更多自由。

@wim︰ 使用collections.Iterable是这包括无限的生成器。这种情况下已更改我的答案句柄。

请输入您的翻译

Flatten (an irregular) list of lists in Python

确认取消