一次循环遍历生成器两个项目



我定义了一个生成器,它从Elasticsearch生成日志条目:

def gen():
    ....
    for hit in results:
        yield hit

如何同时遍历两个元素?以下几行

for one, two in gen():
    ...

我所说的两个元素是指:A, BB, C、...、Y, Z(对于生成的A, B, ..., Y, Z列表(。

这个答案假设你想要不重叠的对。您可以通过zip()执行此操作,因为迭代器被消耗:

for one, two in zip(gen, gen):
    # do something

例:

>>> gen = (x for x in range(5))
>>> for one, two in zip(gen, gen): print(one,two)
... 
0 1
2 3

请注意,正如 timgeb 评论的那样,如果您的元素数量不均匀并且您希望最后一个元素具有填充值,则应使用 itertools.zip_longest,例如:

>>> gen = (x for x in range(5))
>>> for one, two in zip_longest(gen, gen): print(one, two)
... 
0 1
2 3
4 None

回答您更新的问题,使用 itertools.tee 构造第二个迭代器,将第二个迭代器前进一次并丢弃结果,然后使用 zip 成对循环两个迭代器。

>>> from itertools import tee
>>> it = iter('abc')
>>> it1, it2 = tee(it)
>>> 
>>> next(it2, None)
'a'
>>> for first, second in zip(it1, it2):
...     first, second
... 
('a', 'b')
('b', 'c')

谢谢。这是最干净,最"pythonic"的方法吗?我觉得这个简单问题的解决方案就是复杂。

我认为没有更清洁的解决方案。事实上,这是 itertools 文档中pairwise配方:

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

我曾经用以下内容解决了类似的问题:

def gen():
    results = [1, 2, 3, 4, 5]
    for i, v in enumerate(results):
        # if i < len()
        if (i + 1) < len(results):
            yield (v, results[i + 1])
        else:
            yield v

output = gen()
for each in output:
    print(each)

输出将是:

(1, 2)
(2, 3)
(3, 4)
(4, 5)
5

最新更新