robin hood
robin hood

Reputation: 21

Compare dictionaries using python

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

Answers (5)

JL Peyret
JL Peyret

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)

output:

  {
-     "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

Pavan
Pavan

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

Martijn Pieters
Martijn Pieters

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

jonrsharpe
jonrsharpe

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

tobias_k
tobias_k

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

Related Questions