如何逐次分别迭代多个生成器

2017-08-24 16:26:11 +08:00
 billion

我想先从第一个生成器取第 1 个值,从第二个生成器取第 1 个值,从第三个生成器取第 1 个值

接下来从第一个生成器取第 2 个值,从第二个生成器取第 2 个值,从第三个生成器取第 2 个值

以此类推,

最后从第一个生成器取第 5 个值,从第二个生成器取第 5 个值,从第三个生成器取第 5 个值

a = (x for x in range(1, 6))
b = (x for x in range(6, 11))
c = (x for x in range(11, 16))

d = (x for x in [a, b, c])

def y():
    for m in d:
        yield next(m)
for i in y():
    print(i)

我想实现的输出为:

1
6
11
2
7
12
3
8
13
4
9
14
5
10
15

但是,上面的代码由于生成器只能被完整迭代一次所以在 for m in d:这个位置就会出问题。最后只能得到 1, 6, 11

请问有什么比较好的办法解决实现这个需求吗?

这个问题,是为了实现逐行对比超大 Log。我想一行一行对比 Log,但是由于三个 Log 各自都超过了 40G,因此想通过生成器的这种方式来实现。

2296 次点击
所在节点    Python
25 条回复
dsg001
2017-08-24 19:17:45 +08:00
![]( https://ooo.0o0.ooo/2017/08/24/599eb5bfe80ab.png)
billion
2017-08-24 21:05:41 +08:00
@wwqgtxx iter(生成器)这样写的话,生成器里面的东西会被提前放出来吗?
wwqgtxx
2017-08-24 21:49:57 +08:00
@billion 在 Py3 中如果你写成(x for x in range (10)) 则不会,如果写成[x for x in range (10)]就会
NoAnyLove
2017-08-24 23:56:13 +08:00
可以用 yield from 语句
NoAnyLove
2017-08-25 08:11:14 +08:00
发现我在#24 楼说错了,yield from 会从生成器中挨个提取完才发挥

@billion iter 函数调用对象的__iter__()方法; generator 是 iterator 的子类,iterator 要求实现__iter__()方法,并返回自身。所以 iter(生成器) 实际上直接返回了生成器。

另外,在#18 的基础上,如果生成器长度不同,且生成器中没有 None,可以用 filter 进行处理:

```python3
def another_roundrobin(*iterables):
for i in itertools.zip_longest(*iterables, fillvalue=None):
yield from filter(lambda x: x is not None, i)
```

PS:itertools 文档中,Itertools Recipes 章节的 roundrobin 函数写得非常巧妙

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/385494

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX