You can use recursion:
a_standard = {
'section1': {
'category1': 1,
'category2': 2
},
'section2': {
'category1': 1,
'category2': 2
}
}
a_new = {
'section1': {
'category1': 1,
'category2': 2
},
'section2': {
'category1': 1,
'category2': 3
}
}
def differences(a, b, section=None):
return [(c, d, g, section) if all(not isinstance(i, dict) for i in [d, g]) and d != g else None if all(not isinstance(i, dict) for i in [d, g]) and d == g else differences(d, g, c) for [c, d], [h, g] in zip(a.items(), b.items())]
n = filter(None, [i for b in differences(a_standard, a_new) for i in b])
Output:
[('category2', 2, 3, 'section2')]
Which yields the key corresponding to the unequal values.
Edit: without list comprehension:
def differences(a, b, section = None):
for [c, d], [h, g] in zip(a.items(), b.items()):
if not isinstance(d, dict) and not isinstance(g, dict):
if d != g:
yield (c, d, g, section)
else:
for i in differences(d, g, c):
for b in i:
yield b
print(list(differences(a_standard, a_new)))
Output:
['category2', 2, 3, 'section2']
This solution utilizes generators (hence the yield
statement), which store the yielded values on the fly, only remembering where it left off. The values can be garnered by casting the returned result as a list. yield
makes it easier to accumulate the value differences and removes the need to keep an additional parameter in the function or a global variable.