2017-05-08 52 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