Reputation: 21
I have to compare 2 dictionaries in python. For example I used the below code, it's working fine if the number of key:value pair are same in di1 and di2 but if the key:value pair is missing in di2 then code fails.
di1 = {'Name': 'cat', 'Age': 9,'Alpha':'mat','Beta':'deep'};
di2 = {'Name': 'cat', 'Age': 27,'Alpha':'rat'};
dicdiff = [k for k in di1 if di1[k] != di2[k]]
for k in dicdiff:
print k, ':', di1[k], '->', di2[k]
Upvotes: 2
Views: 508
Reputation: 12214
Assuming you want a human-readable output, rather than producing some complex data structure to feed to another bit of your code...
A lot of times you can fall back to existing diff libraries.
I do this all the time with diff
or graphic comparison apps (Windiff, Winmerge, Kaleidoscope, etc...).
You just have to massage the data a bit in advance. For dictionaries, use json.dump(s)(<obj>, sort_keys=True, indent=4)
Here's a go using difflib
in pure Python:
di1 = {'Name': 'cat', 'Age': 9,'Alpha':'mat','Beta':'deep'};
di2 = {'Name': 'cat', 'Age': 27,'Alpha':'rat'};
import difflib
import json
differ = difflib.Differ()
text1 = json.dumps(di1, sort_keys=True, indent=4)
text2 = json.dumps(di2, sort_keys=True, indent=4)
li1 = text1.splitlines()
li2 = text2.splitlines()
diff = differ.compare(li1, li2)
for line in diff:
print(line)
{
- "Age": 9,
? ^
+ "Age": 27,
? ^^
- "Alpha": "mat",
? ^
+ "Alpha": "rat",
? ^
- "Beta": "deep",
"Name": "cat"
}
You could even use assert di1 == di2
to figure out equality first and then only build the big compare stuff on an AssertionError
.
Changing d2 to make it a bit more complex with nesting:
di2 = {'Name': 'cat', 'Age': 27,'Alpha':'rat', "nested" : {"child1":"foo","child2":"bar"}};
gives:
(truncated the bits that stayed the same)
- "Beta": "deep",
- "Name": "cat"
+ "Name": "cat",
? ++
+ "nested": {
+ "child1": "foo",
+ "child2": "bar"
+ }
}
Upvotes: 0
Reputation: 348
di1 = {'Name': 'cat', 'Age': 9,'Alpha':'mat','Beta':'deep'}
di2 = {'Name': 'cat', 'Age': 27,'Alpha':'rat', 'currency':'INR'}
# find intersection
intersection=filter(di1.has_key, di2.keys())
keysnotindi2=list(set(di1.keys())-set(intersection))
keysnotindi1=list(set(di2.keys())-set(intersection))
# by looping on keysnotindi2 and keysnotindi1 you can get values of that particular key
Upvotes: 0
Reputation: 1125168
Use dictionary view objects and use set operations:
for key, value in di1.viewitems() ^ di2.viewitems():
print '{!r}: {!r}'.format(key, value)
^
gives us the symmetric difference between the two dictionaries; this will list keys present in either dictionary but missing from the other, and values that differ.
This produces:
>>> di1 = {'Name': 'cat', 'Age': 9,'Alpha':'mat','Beta':'deep'};
>>> di2 = {'Name': 'cat', 'Age': 27,'Alpha':'rat'};
>>> for key, value in di1.viewitems() ^ di2.viewitems():
... print '{!r}: {!r}'.format(key, value)
...
'Alpha': 'rat'
'Alpha': 'mat'
'Beta': 'deep'
'Age': 27
'Age': 9
You can refine this a little more by looking only at the keys in one or the other dictionary:
print 'Added keys'
for key in di2.viewkeys() - di1.viewkeys():
print '{!r}: {!r}'.format(key, di2[key])
print 'Removed keys'
for key in di1.viewkeys() - di2.viewkeys():
print '{!r}: {!r}'.format(key, di1[key])
print 'Changed keys'
for key in di1.viewkeys() & di2.viewkeys():
if di1[key] != di2[key]:
print '{!r}: {!r} -> {!r}'.format(key, di1[key], di2[key])
This produces:
>>> print 'Added keys'
Added keys
>>> for key in di2.viewkeys() - di1.viewkeys():
... print '{!r}: {!r}'.format(key, di2[key])
...
>>> print 'Removed keys'
Removed keys
>>> for key in di1.viewkeys() - di2.viewkeys():
... print '{!r}: {!r}'.format(key, di1[key])
...
'Beta': 'deep'
>>> print 'Changed keys'
Changed keys
>>> for key in di1.viewkeys() & di2.viewkeys():
... if di1[key] != di2[key]:
... print '{!r}: {!r} -> {!r}'.format(key, di1[key], di2[key])
...
'Alpha': 'mat' -> 'rat'
'Age': 9 -> 27
Upvotes: 4
Reputation: 122157
One way to do this is to create a set
of all keys across both dictionaries, then use dict.get
to handle cases where the key isn't in one of the dictionaries (note that object() != object()
- you could use None
if that will never be an actual value):
def compare(d1, d2):
"""Returns a list of keys that have different values."""
return [k for k in set(d1).union(d2)
if d1.get(k, object()) != d2.get(k, object())]
In use:
>>> d1 = {'Name': 'cat', 'Age': 9,'Alpha':'mat', 'Beta':'deep'}
>>> d2 = {'Name': 'cat', 'Age': 27, 'Alpha':'rat', 'Gamma': 'foo'}
>>> for k in compare(d1, d2):
print "{0}: {1} -> {2}".format(k, d1.get(k, "<missing>"), d2.get(k, "<missing>"))
Age: 9 -> 27
Beta: deep -> <missing>
Alpha: mat -> rat
Gamma: <missing> -> foo
Upvotes: 0
Reputation: 82949
You can create the set union of the keys from both dictionaries and test whether they are missing in one of the dictionaries or whether they are different.
for k in set(di1).union(set(di2)):
if k not in di1:
print k, "missing in di1"
elif k not in di2:
print k, "missing in di2"
elif di1[k] != di2[k]:
print k, ':', di1[k], '->', di2[k]
Upvotes: 0