2014-12-03 4 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' и 'newa' (другими словами d1 мой старый ДИКТ и d2 мой новый ДИКТ).

Я хочу перебирать эти словари таким образом, чтобы ключ был одинаковым для его значения (вложенный dict), например. когда я найду ключ 'a' в d2, я проверю, есть ли 'b', если да, то значение 'cs' (изменено с 10 на 30), если это значение изменено, я хочу его распечатать.

Другой случай, я хочу получить ключ 'newa' от d2 как новый добавленный ключ.

Таким образом, после того, как перебор этих 2 dicts, это ожидаемый результат:

"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

модифицированная USER3, чтобы сделать его еще лучше

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) 
Смежные вопросы