转置嵌套的生成器

时间:2015-11-13 18:53:38

标签: python

是否有明确的方法来迭代列表中每个生成器的项目?我认为展示问题本质的最简单方法是证明是一个例子。这是

0。假设我们有一个函数返回生成器:

def gen_fun(hint):
    for i in range(1,10):
        yield "%s %i" % (hint, i)

1。使用直接迭代顺序的清晰解决方案:

hints = ["a", "b", "c"]
for hint in hints:
    for  txt in gen_fun(hint):
        print(txt)

打印

a 1
a 2
a 3
...
b 1
b 2
b 3
...

2。具有反向迭代次序的繁琐解决方案

hints = ["a", "b", "c"]
generators = list(map(gen_fun, hints))
any = True
while any:
    any = False
    for g in generators:
        try:
            print(next(g))
            any = True
        except StopIteration:
            pass

打印

a 1
b 1
c 1
a 2
b 2
...

这可以按预期工作,做我想要的。

奖励积分:

同样的任务,但gen_fun范围可能不同,即

def gen_fun(hint):
    if hint == 'a':
        m = 5
    else:
        m = 10
    for i in range(1,m):
        yield "%s %i" % (hint, i)

此案例的正确输出是:

a 1
b 1
c 1
a 2
b 2
c 2
a 3
b 3
c 3
a 4
b 4
c 4
b 5
c 5
b 6
c 6
b 7
c 7
b 8
c 8
b 9
c 9

问题:

有没有办法实现 case 2 清理工具?

2 个答案:

答案 0 :(得分:3)

如果我正确理解了这个问题,您可以使用zip()来实现与整个while any循环相同的事情:

hints = ["a", "b", "c"]
generators = list(map(gen_fun, hints))
for x in zip(*generators):
    for txt in x:
        print(txt)

输出:

a 1
b 1
c 1
a 2
b 2
...

更新:

如果发电机的长度不同,拉链“修剪”它们都是最短的。您可以使用itertools.izip_longest(由this q/a建议)来实现相反的行为并继续屈服,直到最长的生成器耗尽。您需要过滤掉填充的值:

hints = ["a", "b", "c"]
generators = list(map(gen_fun, hints))
for x in zip_longest(*generators):
    for txt in x:
        if txt:
            print(txt)

答案 1 :(得分:0)

您可能需要查看itertools.product

from itertools import product

# Case 1
for tup in product('abc', range(1,4)):
    print('{0} {1}'.format(*tup))

print '---'

# Case 2
from itertools import product
for tup in product(range(1,4), 'abc'):
    print('{1} {0}'.format(*tup))

输出:

a 1
a 2
a 3
b 1
b 2
b 3
c 1
c 2
c 3
---
a 1
b 1
c 1
a 2
b 2
c 2
a 3
b 3
c 3

请注意,案例1和案例2之间的差异只是传递到product函数和print语句的参数的顺序。