2014-09-11 61 views
2

這是Generator to yield gap tuples from zipped iterables上的變體。生成器合併排序字典式迭代器

我希望設計發電機功能是:

  • 接受iterables
  • 每個輸入迭代產生零個或多個任意數目的(K,V)中,k不一定是唯一的
  • 輸入鍵假定按升序進行排序
  • 輸出應該產生(k, (v1, v2, ...))
  • 輸出鍵獨一無二的,應用程序耳以相同的順序與輸入
  • 輸出元組的數目等於唯一鍵的輸入
  • 的輸出值對應於所有輸入數元組相匹配的輸出密鑰
  • 由於輸入和輸出它們可能很大,它們應該被視爲可迭代的對象,並且不會作爲內存中的字典或列表加載。

舉個例子,

i1 = ((2, 'a'), (3, 'b'), (5, 'c')) 
i2 = ((1, 'd'), (2, 'e'), (3, 'f')) 
i3 = ((1, 'g'), (3, 'h'), (5, 'i'), (5, 'j')) 
result = sorted_merge(i1, i2, i3) 
print [result] 

這將輸出:

[(1, ('d', 'g')), (2, ('a', 'e')), (3, ('b', 'f', 'h')), (5, ('c', 'i', 'j'))] 

如果我沒有記錯的話,沒有什麼內置到Python標準庫做到這一點開箱。

回答

3

雖然沒有一個單一的標準庫函數來完成你想要什麼,有enoughbuildingblocks讓你最方式:

from heapq import merge 
from itertools import groupby 
from operator import itemgetter 

def sorted_merge(*iterables): 
    for key, group in groupby(merge(*iterables), itemgetter(0)): 
     yield key, [pair[1] for pair in group]  

例子:

>>> i1 = ((2, 'a'), (3, 'b'), (5, 'c')) 
>>> i2 = ((1, 'd'), (2, 'e'), (3, 'f')) 
>>> i3 = ((1, 'g'), (3, 'h'), (5, 'i'), (5, 'j')) 
>>> result = sorted_merge(i1, i2, i3) 
>>> list(result) 
[(1, ['d', 'g']), (2, ['a', 'e']), (3, ['b', 'f', 'h']), (5, ['c', 'i', 'j'])] 

注在上面的版本sorted_merge中,爲了產生可讀輸出,我們產生intlist對。如果你想獲得int<generator>雙反而沒有什麼阻止你改變相關的行

 yield key, (pair[1] for pair in group)   

+0

我想我會做這個(除了你的建議的產生變化),唯一的修改是用一個簡單的lambda來代替itemgetter。 – Reinderien 2014-09-12 17:28:59

+0

@Reinderien您的選擇當然,但爲什麼?這正是'itemgetter'的用處......它更短,海事組織更具可讀性,可能更快。 – 2014-09-12 17:33:35

+0

減少一次導入,減少一個文檔必須讀取的功能,另一種方法很簡單。儘管如此,這只是勉強。 – Reinderien 2014-09-12 17:44:42

0

的東西有點不同:

from collections import defaultdict 

def sorted_merged(*items): 
    result = defaultdict(list) 
    for t in items: 
     for k, v in t: 
      result[k].append(v) 
    return sorted(list(result.items())) 

i1 = ((2, 'a'), (3, 'b'), (5, 'c')) 
i2 = ((1, 'd'), (2, 'e'), (3, 'f')) 
i3 = ((1, 'g'), (3, 'h'), (5, 'i'), (5, 'j')) 

result = sorted_merged(i1, i2, i3) 
+0

不幸的是默認字典會吃掉我的記憶。 – Reinderien 2014-09-11 12:55:27