2014-12-03 214 views
7

我知道這裏有幾個類似的問題,但是我的問題對我來說很不一樣,也很困難。 我有兩個字典:比較Python字典和嵌套字典

d1 = {'a': {'b': {'cs': 10}, 'd': {'cs': 20}}} 
d2 = {'a': {'b': {'cs': 30}, 'd': {'cs': 20}}, 'newa': {'q': {'cs': 50}}} 

d1具有關鍵'a',並d2具有鍵'a'和​​(換句話說d1是我的老字典和d2是我的新字典)。

我想遍歷這些字典,如果鍵是相同的檢查其值(嵌套字典),例如,當我找到鑰匙'a'd2,我會檢查是否有'b',如果是檢查值'cs'(從10更改爲30),如果這個值改變,我想打印它。

另一種情況是,我想從d2獲取密鑰​​作爲新添加的密鑰。

因此,通過這兩個類型的字典迭代後,這是預期的輸出:

"d2" has new key "newa" 
Value of "cs" is changed from 10 to 30 of key "b" which is of key "a" 

我已經把下面的代碼,我與未盡管工作很多圈很努力,但不是不錯的選擇,因此我正在尋找是否可以通過遞歸代碼獲得預期的輸出。

for k, v in d1.iteritems(): 
    for k1, v1 in d2.iteritems(): 
     if k is k1: 
      print k 
      for k2 in v: 
       for k3 in v1: 
        if k2 is k3: 
         print k2, "sub key matched" 

     else: 
      print "sorry no match found" 

回答

9

比較使用遞歸2點字典:

d1= {'a':{'b':{'cs':10},'d':{'cs':20}}} 
d2= {'a':{'b':{'cs':30} ,'d':{'cs':20}},'newa':{'q':{'cs':50}}} 

def findDiff(d1, d2, path=""): 
    for k in d1.keys(): 
     if not d2.has_key(k): 
      print path, ":" 
      print k + " as key not in d2", "\n" 
     else: 
      if type(d1[k]) is dict: 
       if path == "": 
        path = k 
       else: 
        path = path + "->" + k 
       findDiff(d1[k],d2[k], path) 
      else: 
       if d1[k] != d2[k]: 
        print path, ":" 
        print " - ", k," : ", d1[k] 
        print " + ", k," : ", d2[k] 

print "comparing d1 to d2:" 
print findDiff(d1,d2) 
print "comparing d2 to d1:" 
print findDiff(d2,d1) 

輸出:

comparing d1 to d2: 
a->b : 
- cs : 10 
+ cs : 30 
None 
comparing d2 to d1: 
a->b : 
- cs : 30 
+ cs : 10 
a : 
newa as key not in d2 

None 
2

這應該提供您需要提供有用的功能是什麼:

對於Python 2.7

def isDict(obj): 
    return obj.__class__.__name__ == 'dict' 

def containsKeyRec(vKey, vDict): 
    for curKey in vDict: 
     if curKey == vKey or (isDict(vDict[curKey]) and containsKeyRec(vKey, vDict[curKey])): 
      return True 
    return False 

def getValueRec(vKey, vDict): 
    for curKey in vDict: 
     if curKey == vKey: 
      return vDict[curKey] 
     elif isDict(vDict[curKey]) and getValueRec(vKey, vDict[curKey]): 
      return containsKeyRec(vKey, vDict[curKey]) 
    return None 

d1= {'a':{'b':{'cs':10},'d':{'cs':20}}} 
d2= {'a':{'b':{'cs':30} ,'d':{'cs':20}},'newa':{'q':{'cs':50}}} 

for key in d1: 
    if containsKeyRec(key, d2): 
     print "dict d2 contains key: " + key 
     d2Value = getValueRec(key, d2) 
     if d1[key] == d2Value: 
      print "values are equal, d1: " + str(d1[key]) + ", d2: " + str(d2Value) 
     else: 
      print "values are not equal, d1: " + str(d1[key]) + ", d2: " + str(d2Value) 

    else: 
     print "dict d2 does not contain key: " + key 

對於Python 3(或更高):

def id_dict(obj): 
    return obj.__class__.__name__ == 'dict' 


def contains_key_rec(v_key, v_dict): 
    for curKey in v_dict: 
     if curKey == v_key or (id_dict(v_dict[curKey]) and contains_key_rec(v_key, v_dict[curKey])): 
      return True 
    return False 


def get_value_rec(v_key, v_dict): 
    for curKey in v_dict: 
     if curKey == v_key: 
      return v_dict[curKey] 
     elif id_dict(v_dict[curKey]) and get_value_rec(v_key, v_dict[curKey]): 
      return contains_key_rec(v_key, v_dict[curKey]) 
    return None 


d1 = {'a': {'b': {'cs': 10}, 'd': {'cs': 20}}} 
d2 = {'a': {'b': {'cs': 30}, 'd': {'cs': 20}}, 'newa': {'q': {'cs': 50}}} 

for key in d1: 
if contains_key_rec(key, d2): 
    d2_value = get_value_rec(key, d2) 
    if d1[key] == d2_value: 
     print("values are equal, d1: " + str(d1[key]) + ", d2: " + str(d2_value)) 
     pass 
    else: 
     print("values are not equal:\n" 
       "list1: " + str(d1[key]) + "\n" + 
       "list2: " + str(d2_value)) 

else: 
    print("dict d2 does not contain key: " + key) 
4

改性用戶3的代碼,以使其更好

d1= {'as': 1, 'a': 
     {'b': 
      {'cs':10, 
      'qqq': {'qwe':1} 
      }, 
      'd': {'csd':30} 
     } 
    } 
d2= {'as': 3, 'a': 
     {'b': 
      {'cs':30, 
      'qqq': 123 
      }, 
      'd':{'csd':20} 
     }, 
     'newa': 
     {'q': 
      {'cs':50} 
     } 
    } 

def compare_dictionaries(dict_1, dict_2, dict_1_name, dict_2_name, path=""): 
    """Compare two dictionaries recursively to find non mathcing elements 

    Args: 
     dict_1: dictionary 1 
     dict_2: dictionary 2 

    Returns: 

    """ 
    err = '' 
    key_err = '' 
    value_err = '' 
    old_path = path 
    for k in dict_1.keys(): 
     path = old_path + "[%s]" % k 
     if not dict_2.has_key(k): 
      key_err += "Key %s%s not in %s\n" % (dict_2_name, path, dict_2_name) 
     else: 
      if isinstance(dict_1[k], dict) and isinstance(dict_2[k], dict): 
       err += compare_dictionaries(dict_1[k],dict_2[k],'d1','d2', path) 
      else: 
       if dict_1[k] != dict_2[k]: 
        value_err += "Value of %s%s (%s) not same as %s%s (%s)\n"\ 
         % (dict_1_name, path, dict_1[k], dict_2_name, path, dict_2[k]) 

    for k in dict_2.keys(): 
     path = old_path + "[%s]" % k 
     if not dict_1.has_key(k): 
      key_err += "Key %s%s not in %s\n" % (dict_2_name, path, dict_1_name) 

    return key_err + value_err + err 


a = compare_dictionaries(d1,d2,'d1','d2') 
print a 

輸出:

Key d2[newa] not in d1 
Value of d1[as] (1) not same as d2[as] (3) 
Value of d1[a][b][cs] (10) not same as d2[a][b][cs] (30) 
Value of d1[a][b][qqq] ({'qwe': 1}) not same as d2[a][b][qqq] (123) 
Value of d1[a][d][csd] (30) not same as d2[a][d][csd] (20)