2017-05-08 104 views
6

两个项目我已经定义了一个发生器,产生从Elasticsearch日志条目:遍历发生器同时

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

我怎么能遍历两个元素在同一时间?东西的线路:

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

通过两个元素我的意思是这样的:A, BB, C,...,Y, Z(为A, B, ..., Y, Z生成的列表)。

回答

6

回答您的问题更新,使用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 docspairwise配方:

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

谢谢。这是最干净,最“pythonic”的方式吗?我觉得这个简单问题的解决方案很复杂。 – linkyndy

+0

感谢您指出itertools配方! – linkyndy

+1

@AndreiHorak没有问题,如果你使用的是Python 2,请确保使用'izip',特别是如果你的迭代器/生成器可以产生无限量的对象。 – timgeb

6

这个答案假设你想要非重叠对。因为迭代器消耗您可以通过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 
+0

这是否会确保相同的顺序元素和以前加载的项目的重用? – linkyndy

+2

请注意,如果发生器产生的对象数量不均匀,这将不会产生最后一个元素。在这种情况下,使用'itertools.izip_longest'将会得到'(last_element,None)'(或者你想要的任何填充值)。 – timgeb

+0

@AndreiHorak你是什么意思,“重复使用先前加载的项目”? – timgeb

0

我一旦解决了类似的问题,以下内容:

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 
+0

由于生成器循环遍历分页的Elasticsearch结果,因此我认为将所有内容加载到内存中并不是最佳选择,以便将项目逐个分组。 – linkyndy