在 itertools
中有 chain
,它将多个生成器组合成一个,本质上对它们进行深度优先迭代,即 chain。 from_iterable(['ABC', '123'])
产生 A、B、C、1、2、3。但是,没有广度优先版本,还是我遗漏了什么?当然有 izip_longest
,但是对于大量的生成器来说这感觉很尴尬,因为元组会很长而且可能非常稀疏。
我想到了以下内容:
def chain_bfs(*generators):
generators = list(generators)
while generators:
g = generators.pop(0)
try:
yield g.next()
except StopIteration:
pass
else:
generators.append(g)
我觉得有点冗长,我是否缺少更 Pythonic 的方法?这个函数是否适合包含在 itertools
中?
最佳答案
你可以使用 collections.deque()
通过你的迭代器旋转;旋转双端队列效率更高。我也将其称为链式 zipper ,而不是“呼吸链”,如下所示:
from collections import deque
def chained_zip(*iterables):
iterables = deque(map(iter, iterables))
while iterables:
try:
yield next(iterables[0])
except StopIteration:
iterables.popleft()
else:
iterables.rotate(-1)
演示:
>>> list(chained_zip('ABC', '123'))
['A', '1', 'B', '2', 'C', '3']
>>> list(chained_zip('AB', '1234'))
['A', '1', 'B', '2', '3', '4']
还有一个roundrobin()
recipe in the documentation做同样的事情,使用 itertools.cycle()
function :
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
pending = len(iterables)
nexts = cycle(iter(it).__next__ for it in iterables)
while pending:
try:
for next in nexts:
yield next()
except StopIteration:
pending -= 1
nexts = cycle(islice(nexts, pending))
关于python - itertools.chain() 的广度优先版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23874228/