2014-12-03 210 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)