[英]Generator function that yields alternating values of two lists
The question seems very basic and easy at first glance, but I still had some trouble writing an efficient solution.这个问题乍一看似乎非常基础和简单,但我在编写有效的解决方案时仍然遇到了一些麻烦。 The idea is to write a function, which takes two generators as an input and yields one item of each list.
想法是编写一个 function,它以两个生成器作为输入并生成每个列表的一项。 If either list is empty, it yields each item of the remaining list.
如果任一列表为空,则生成剩余列表的每个项目。 Example:
例子:
list(alternate("abcdefg", [1, 2, 3, 4])) == ["a", 1, "b",2, "c", 3, "d", 4, "e", "f", "g"]
what kind of worked, but looks very ugly:什么样的工作,但看起来很丑陋:
def alternate(xs1, xs2):
xs1 = iter(xs1)
xs2 = iter(xs2)
while xs1 and xs2:
try:
yield next(xs1), next(xs2)
except StopIteration:
for x1 in xs1:
yield x1
for x2 in xs2:
yield x2
Especially I want to avoid transforming the inputs to an iterator in the beginning.特别是我想避免在开始时将输入转换为迭代器。 I tried using 2 simple for loops, but this obviously returned only the last value of each list, because one for loops finishes before the other starts.
我尝试使用 2 个简单的 for 循环,但这显然只返回每个列表的最后一个值,因为一个 for 循环在另一个循环开始之前完成。 This is not a solve my problem question, I am rather looking for some code to improve writing code skills!
这不是解决我的问题的问题,我是在寻找一些代码来提高编写代码的技巧!
Use zip_longest
and chain.from_iterable
together:一起使用
zip_longest
和chain.from_iterable
:
>>> from itertools import chain, zip_longest
>>> [ x for x in chain.from_iterable(zip_longest("abcdefg", [1,2,3,4])) if x is not None]
['a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 'f', 'g']
For something more explicit and similar to what you already have, handle each call to next
separately, and break out of the loop immediately to iterate over the remainder of each iterator.对于更明确且与您已经拥有的内容相似的内容,请分别处理对
next
的每个调用,并立即跳出循环以迭代每个迭代器的其余部分。 Use itertools.cycle
to alternate between the two iterators until one is exhausted.使用
itertools.cycle
在两个迭代器之间交替,直到一个迭代器用完。
from itertools import cycle
def alternate(xs1, xs2):
xs1 = iter(xs1)
xs2 = iter(xs2)
for itr in cycle([xs1, xs2]):
try:
yield next(itr)
except StopIteration:
break
yield from xs1
yield from xs2
I prefer the above answer but here's a version that doesn't use any imports:我更喜欢上面的答案,但这是一个不使用任何导入的版本:
def alternate(xs1, xs2):
xs1, xs2 = iter(xs1), iter(xs2)
for e1, e2 in zip(xs1, xs2): # either xs1, xs2 exhausted by the end of this loop
yield e1
yield e2
# pull remaining from the non-exhausted generator (if any)
yield from xs1
yield from xs2
If you want a version that doesn't transform the inputs into iterators and avoids using other libraries, the below would work, assuming both sequences are indexable.如果您想要一个不将输入转换为迭代器并避免使用其他库的版本,假设两个序列都是可索引的,则下面的方法将起作用。
def alternate2(xs1, xs2):
n = min(len(xs1), len(xs2))
for i in range(n):
yield xs1[i]
yield xs2[i]
yield from xs1[n:]
yield from xs2[n:]
It's going to be challenging to do away with iter()
, as that's kind of what it's made for.取消
iter()
将具有挑战性,因为这就是它的目的。 If you can put up with that, this can be straightforward:如果你能忍受,这可能很简单:
def alternate(a, b):
ia = iter(a)
ib = iter(b)
while True:
try:
yield next(ia)
yield next(ib)
except StopIteration:
break
yield from ia
yield from ib
This is slightly simpler than @wLui's:这比@wLui 的稍微简单一些:
def alternate(xs1, xs2):
xs1 = iter(xs1)
xs2 = iter(xs2)
for pair in zip(xs1, xs2):
yield from pair
yield from xs1
yield from xs2
(This is basically @chepner's answer from the comments, but I believe this is the right answer which deserves to appear here...) (这基本上是@chepner 从评论中得到的回答,但我相信这是正确的答案,值得出现在这里……)
You can use the roundrobin
function from the more-itertools project (referenced from python docs ).您可以使用more-itertools 项目中的
roundrobin
function(引用自python 文档)。
I include it here for convenience:为了方便起见,我把它包括在这里:
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
num_active = len(iterables)
nexts = cycle(iter(it).__next__ for it in iterables)
while num_active:
try:
for next in nexts:
yield next()
except StopIteration:
# Remove the iterator we just exhausted from the cycle.
num_active -= 1
nexts = cycle(islice(nexts, num_active))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.