创建迭代器以逐个从每个可迭代对象返回元素

2024-09-24 12:24:40 发布

您现在位置:Python中文网/ 问答频道 /正文

我在学习itertools模块,并尝试创建一个迭代器,从作为输入提供的iterables返回每个元素。在

Agruments   Results
p, q, …     p0, q0, … plast, qlast 

还有一个附加条款,如果说列表的长度不一样,那么当较短的列表用完时,next(it)应该从较长的列表中返回元素。在

尝试解决

^{pr2}$

哪种解决了我的问题

print(list(it))

输出:

[1, 'a', 2, 'b', 3, 'c', 4, 'd', 5, 6]

有没有更简单或更好的方法?我想找个办法解决这个问题,但没能找到。在


Tags: 模块元素列表itresults条款nextitertools
2条回答

可以使用^{}展平序列,并使用生成器表达式筛选出None值:

from itertools import chain, zip_longest

it = (v for v in chain.from_iterable(zip_longest(l1, l2)) if v is not None)

您可能不想使用None作为sentinel值,而是希望使用专用的sentinel,以便可以在输入列表中使用None

^{pr2}$

如果要筛选出falsey values,则还可以使用^{}

it = filter(None, chain.from_iterable(zip_longest(l1, l2)))

演示:

>>> from itertools import chain, zip_longest
>>> l1 = [1, 2, 3, 4, 5, 6]
>>> l2 = ['a', 'b', 'c', 'd']
>>> it = (v for v in chain.from_iterable(zip_longest(l1, l2)) if v is not None)
>>> list(it)
[1, 'a', 2, 'b', 3, 'c', 4, 'd', 5, 6]

还有当地的哨兵:

>>> l1 = [1, None, 2, None, 3, None]
>>> l2 = ['a', 'b', 'c', 'd']
>>> _sentinel = object()
>>> flattened = chain.from_iterable(zip_longest(l1, l2, fillvalue=_sentinel))
>>> it = (v for v in flattened if v is not _sentinel)
>>> list(it)
[1, 'a', None, 'b', 2, 'c', None, 'd', 3, None]

^{} recipes section还具有:

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))

如果您希望修改代码版本,请从一开始就构建一个生成器(无存储列表l):

import itertools
l1=[1,2,3,4,5,6]
l2=['a','b','c','d']

def flat_zip(l1,l2):
    for x,y in itertools.zip_longest(l1,l2):
        if x:
            yield x
        if y:
            yield y
it=flat_zip(l1,l2)

尽管我建议使用上面的内置解决方案。在

相关问题 更多 >