2016-12-05 80 views
1

我想在字典中識別並分組重複值。要做到這一點,我建立一個僞哈希(更好地閱讀簽名)我的數據集如下的:在字典中查找混合類型值的重複項

from pickle import dumps 
taxonomy = {} 
binder = defaultdict(list) 
for key, value in ds.items(): 
    signature = dumps(value) 
    taxonomy[signature] = value 
    binder[signature].append(key) 

對於具體使用情況請參閱本question

不幸的是,我意識到,如果下面的語句是True

>>> ds['key1'] == ds['key2'] 
True 

這個人是不是總是True了:

>>> dumps(ds['key1']) == dumps(ds['key2']) 
False 

我注意到在傾倒輸出鍵順序兩個字典不同。如果我拷貝/粘貼ds['key1']ds['key2']的輸出成新詞典我可以比較成功。

作爲一個矯枉過正的替代,我可以遞歸遍歷我的數據集,並與OrderedDict替換dict實例:

import copy 
def faithfulrepr(od): 
    od = od.deepcopy(od) 
    if isinstance(od, collections.Mapping): 
     res = collections.OrderedDict() 
     for k, v in sorted(od.items()): 
      res[k] = faithfulrepr(v) 
     return repr(res) 
    if isinstance(od, list): 
     for i, v in enumerate(od): 
      od[i] = faithfulrepr(v) 
     return repr(od) 
    return repr(od) 

>>> faithfulrepr(ds['key1']) == faithfulrepr(ds['key2']) 
True 

我很擔心這種幼稚的做法,因爲我不知道我是否涵蓋所有可能發生的情況。

可以使用哪些其他(通用)替代方案?

+0

所以,你希望每個'dict'的'repr'是相同的......任何原因不能只是'加載'他們和比較? –

+0

好的,使用'repr'可以比使用'pickle'容易得多。不幸的是,'repr'對象並不總是足以比較兩個實例的內容。這就是說'repr(ds ['key1'])== repr(ds ['key2'])'也會返回False ... – nowox

+0

我的意思是 - 你需要* dict'對象的*表示*比較相等 - 無論是JSON /酸洗/'str''d /'repr''d等等......爲什麼不反過來再比較一下呢?例如:'loads(dumps(ds ['key1']))== loads(dumps(ds ['key2']))'? –

回答

1

的第一件事就是刪除對deepcopy調用哪個是你的瓶頸在這裏:

def faithfulrepr(ds): 
    if isinstance(ds, collections.Mapping): 
     res = collections.OrderedDict(
      (k, faithfulrepr(v)) for k, v in sorted(ds.items()) 
     ) 
    elif isinstance(ds, list): 
     res = [faithfulrepr(v) for v in ds] 
    else: 
     res = ds 
    return repr(res) 

然而sortedrepr有其缺點:

  1. 你不能真實地比較的自定義類型;
  2. 你不能使用不同類型的鍵的映射。

所以第二件事是要擺脫faithfulrepr和比較對象與__eq__

binder, values = [], [] 
for key, value in ds.items(): 
    try: 
     index = values.index(value) 
    except ValueError: 
     values.append(value) 
     binder.append([key]) 
    else: 
     binder[index].append(key) 
grouped = dict(zip(map(tuple, binder), values))