This question already has an answer here:
这个问题在这里已有答案:
If I do:
如果我做:
def foo():
yield from range(0,10)
yield from range(10,20)
for num in foo():
print(num)
I get a ordered list from 0 to 19. Without change the input of the range functions, is there an easy way to specify that I want a list that goes: 0,10,1,11,2,12...
我得到一个从0到19的有序列表。如果没有更改范围函数的输入,是否有一种简单的方法来指定我想要一个列表:0,10,1,11,2,12 ......
Basically I first want the first element of every generator. Than I want the second element of every generator and then the third and so on.
基本上我首先想要每个发生器的第一个元素。比我想要每个发生器的第二个元素然后第三个,依此类推。
Bonus points: Is there a way to change it so that when the generators produce an unequal amount of results, the second generator yields the rest of it's results after the first one is finished?
加分点:有没有办法改变它,以便当发生器产生不等量的结果时,第二个发生器在第一个结束后产生剩下的结果?
7
You are trying to zip()
your iterators; do so explicitly:
你正试图zip()你的迭代器;明确地这样做:
from itertools import chain
def foo():
yield from chain.from_iterable(zip(range(10), range(10, 20)))
The use of itertools.chain.from_iterable()
lets you continue to use yield from
here, flattening out the tuples zip()
produces.
使用itertools.chain.from_iterable()可以让你继续使用此处的yield,展平了zip()生成的元组。
Demo:
演示:
>>> from itertools import chain
>>> def foo():
... yield from chain.from_iterable(zip(range(10), range(10, 20)))
...
>>> list(foo())
[0, 10, 1, 11, 2, 12, 3, 13, 4, 14, 5, 15, 6, 16, 7, 17, 8, 18, 9, 19]
If you have generators of different lengths, you could use itertools.zip_longest()
:
如果你有不同长度的生成器,你可以使用itertools.zip_longest():
from itertools import zip_longest
def foo():
yield from (i for pair in zip_longest(range(10), range(10, 22))
for i in pair if i is not None)
I used a different flattening technique here with a double loop in a generator expression.
我在这里使用了一种不同的展平技术,在生成器表达式中使用了双循环。
This all does get tedious, and since you are not using yield from
with another generator (so you don't need support for generator.send()
and generator.throw()
to be propagated), you may as well just make this a proper loop:
这一切都变得乏味,因为你没有使用另一个生成器的yield(所以你不需要支持generator.send()和generator.throw()来传播),你也可以这样做适当的循环:
def foo():
for x, y in zip_longest(range(10), range(10, 22)):
if x is not None:
yield x
if y is not None:
yield y
You can also use the roundrobin()
recipe listed in the itertools
documentation recipies section:
您还可以使用itertools文档收件人部分中列出的roundrobin()配方:
from itertools import cycle
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))
def foo():
yield from roundrobin(range(10), range(10, 22))
本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.silva-art.net/blog/2014/09/13/35b5f8358e59ed055f4d0b46d91fcfd2.html。