Comparing Python Dictionaries and Nested Dictionaries

I know that there are several similar questions, but my question is completely different and difficult for me. I have two dictionaries:

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

i.e. d1 has the key 'a' , and d2 has the keys 'a' and 'newa' (in other words, d1 is my old dict and d2 is my new dict).

I want to iterate over these dictionaries so that if the key is the same, check its value (nested dict), for example. when I find the key 'a' in d2 , I will check if there is a 'b' , if so, check the value of 'cs' (changed from 10 to 30 ), if this value is changed, I want to print it.

Otherwise, I want to get the key 'newa' from d2 as the newly added key.

Therefore, after iterating through these 2 dicts, this is the expected result:

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

I have the following code with me, I am trying to use a lot of loops that do not work, but this is also not a good option, so I am looking to find out if I can get the expected result using the recursive part of the code.

 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" 
+12
python comparison dictionary
source share
4 answers

comparing 2 dictionaries using recursion:

 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) 

Output:

 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 
+18
source share

Modified user3 code to make it even better

 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 

Output:

 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) 
+10
source share

This should provide what you need with useful features:

For 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 

For Python 3 (or higher):

 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
source share

For Python 3 or higher, code to compare any data.

 def do_compare(data1, data2, data1_name, data2_name, path=""): if operator.eq(data1, data2) and not path: log.info("Both data have same content") else: if isinstance(data1, dict) and isinstance(data2, dict): compare_dict(data1, data2, data1_name, data2_name, path) elif isinstance(data1, list) and isinstance(data2, list): compare_list(data1, data2, data1_name, data2_name, path) else: if data1 != data2: value_err = "Value of %s%s (%s) not same as %s%s (%s)\n"\ % (data1_name, path, data1, data2_name, path, data2) print (value_err) # findDiff(data1, data2) def compare_dict(data1, data2, data1_name, data2_name, path): old_path = path for k in data1.keys(): path = old_path + "[%s]" % k if k not in data2: key_err = "Key %s%s not in %s\n" % (data1_name, path, data2_name) print (key_err) else: do_compare(data1[k], data2[k], data1_name, data2_name, path) for k in data2.keys(): path = old_path + "[%s]" % k if k not in data1: key_err = "Key %s%s not in %s\n" % (data2_name, path, data1_name) print (key_err) def compare_list(data1, data2, data1_name, data2_name, path): data1_length = len(data1) data2_length = len(data2) old_path = path if data1_length != data2_length: value_err = "No: of items in %s%s (%s) not same as %s%s (%s)\n"\ % (data1_name, path, data1_length, data2_name, path, data2_length) print (value_err) for index, item in enumerate(data1): path = old_path + "[%s]" % index try: do_compare(data1[index], data2[index], data1_name, data2_name, path) except IndexError: pass 
+1
source share

All Articles