Python:将包含另一个生成器的生成器展开的函数

9

我想知道如何编写Python函数来展开生成器,该生成器会生成另一个生成器或可迭代对象(也可以生成另一个生成器/可迭代对象...可能是无穷的)。

以下是示例:

gen(gen(1,2,3), gen(4,5,6), [7,8,9], [gen(10,11,12), gen(13,14,15)])

注意: gen - 是生成器对象,括号内是gen所生成的数据。

预期的“展开”后结果为:gen(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)

展开函数必须返回生成器!(否则,前面使用生成器将毫无意义)。

请注意,我正在使用Python 3。

谢谢!

2个回答

15

最简单的方法是使用递归展平函数。 假设你想要遍历所有可迭代对象,但不包括字符串,你可以这样做:

def flatten(it):
    for x in it:
        if (isinstance(x, collections.Iterable) and
            not isinstance(x, str)):
            for y in flatten(x):
                yield y
        else:
            yield x

从Python 3.3开始,你也可以这样写:

def flatten(it):
    for x in it:
        if (isinstance(x, collections.Iterable) and
            not isinstance(x, str)):
            yield from flatten(x)
        else:
            yield x

非常感谢!我尝试了一下,离你的很接近了 :-) 致意! - JoshuaBoshi
+1 - 我总是忘记 yield from,这是一个很好的提醒。 - Jon Clements
2
@JonClements:你竟然“一直忘记”一个尚未发布的Python版本的功能?我很惊讶 :) - Sven Marnach
我的水晶球最近一直在正常工作!? ;) [但是说真的 - 我碰巧遵循PEP规范] - Jon Clements

0
非递归方法本质上是递归方法的展开,使用堆栈:
def flatten(it):
    stack = []
    it = iter(it)
    while True:
        try:
            x = next(it)
        except StopIteration:
            if stack:
                it = stack.pop()
                continue
            else:
                return
        if isinstance(x, collections.Iterable) and not isinstance(x, str):
            stack.append(it)
            it = iter(x)
        else:
            yield x

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接