2016-10-10 43 views
1

我目前面臨着不得不從一個規範的變化源中半定期更新(同步)一個大ish列表的列表,同時保持我自己的更新它。非標準合併,爲此,最簡單的描述大概是: -從一個新的詞典列表更新排序列表(優先合併)

  • A是我自己的類型的字典(通過我的程序,包括緩存的值作爲附加鍵更新列表
  • b是一些經常發送的信息。 (A最初與b相同),它包含幾個鍵,但不包括我已經添加到A的緩存值。
  • keys = ['key1', 'key2']是A和b都有的鍵列表(A有更多鍵
  • mkey = 'mtime'是一個特殊的鍵,A和B都表示我應該A.無效的緩存值

基本上,如果A一個字典中b的字典相匹配,我應該保持在字典一個,除非b['mtime'] > A['mtime']。如果一個字典出現在A但不在b我擺脫它,而如果它出現在b但不在A我將它添加到A

我的聖盃目標是在A中完全不會丟失任何緩存的鍵值對,但我無法實現這一點。我目前的解決方案看起來是這樣的: -

def priority_merge(A, b, keys, mkey): 
    retval = [] 
    b_index = 0 
    for elemA in A: 
     if b_index >= len(b): 
      break # No more items in b 
     elemb = b[b_index] 
     minA = { k: elemA[k] for k in keys } 
     minb = { k: elemb[k] for k in keys } 
     if minA == minb: # Found a match 
      if elemA[mkey] >= elemb[mkey]: 
       retval.append(elemA) 
      else: # Check mkey to see if take b instead 
       retval.append(elemb) 
      b_index = b_index + 1 
     else: # No match, check forward by one 
      if b_index+1 >= len(b): 
       continue 
      elembplus = b[b_index+1] 
      minb = { k: elembplus[k] for k in keys} 
      if minA == minb: 
       retval.append(elemb) # This is a new element 
       if elemA[mkey] >= elembplus[mkey]: 
        retval.append(elemA) 
       else: 
        retval.append(elembplus) 
       b_index = b_index + 2 
    if b_index <= len(b): 
     retval.extend(b[b_index:]) 
    return retval 

這隻要正常工作,因爲我沒有得到連續多個添加和/或缺失(b相對於A)。因此,如果A包含1,2,3,5和b包含1,2,3,4,5,那麼很好,但是如果A包含1,2,5和b包含1,2,3,4,5,則這個分解。

我能做到通過兩個Ab的其他情況下的檢查,直到LEN(二)評價爲# No match, check forward by one,或第一迭代匹配元素映射,然後再通過基於該地圖創建RETVAL上迭代。這看起來很容易出錯(我確定它的可執行邏輯是明智的,但我也確信我爲它編寫的代碼會有問題)。請推薦一個合適的算法來解決這個問題,無論是我的兩個想法還是別的。

+0

你可以哈希您的字典http://stackoverflow.com/questions/9835668/python-dictionary-keyswhich-are-class-objects-comparison-with-multiple-compare和應用集在散列字典列表上進行操作。 –

+0

謝謝@AliSAIDOMAR,但是這並不能回答我對優先級合併算法的問題。散列是爲了使比較本身更有效率,而且我自己做比較時沒有問題(請參閱代碼示例)。 –

回答

0

正如我告訴散列法可以幫助您確保比較,僅基於keys列表您將能夠找到相交元素(要合併元素)和差異元素。

class HashedDictKey(dict): 

    def __init__(self, keys_, **kwargs): 
     super().__init__(**kwargs) 
     self.keys_ = keys_ 

    def __hash__(self): 
     return hash(tuple(sorted((k, self.get(k)) for k in self.keys_))) 

    def __eq__(self, other): 
     return hash(self) == hash(other) 

def merge(A, B): 

    to_be_added = [] 
    to_be_del = [] 
    to_be_updated = [] 

    def get(obj, it): 
     for i in it: 
      if obj == i: 
       return i 
     raise ValueError("No %s value" % obj) 

    for a, b in zip_longest(A, B): 
     if a in B: 
      to_be_updated.append(a) 
     if a not in B: 
      to_be_del.append(a) 
     if b not in A: 
      to_be_added.append(b) 

    for i in to_be_del: 
     A.remove(i) 

    for j in to_be_added: 
     A.append(j) 

    for i in to_be_updated: 
     a = get(i, A) 
     b = get(i, B) 
     if b['mtime'] > a['mtime']: 
      A.remove(a) 

here the complete snippet