Is there a better way to compare dictionary values

I am currently using the following function to compare dictionary values and display all the values that don't match. Is there a faster or better way to do it?

match = True
for keys in dict1:
if dict1[keys] != dict2[keys]:
match = False
print keys
print dict1[keys],
print  '->' ,
print dict2[keys]

Edit: Both the dicts contain the same keys.

180426 次浏览

If you're just comparing for equality, you can just do this:

if not dict1 == dict2:
match = False

Otherwise, the only major problem I see is that you're going to get a KeyError if there is a key in dict1 that is not in dict2, so you may want to do something like this:

for key in dict1:
if not key in dict2 or dict1[key] != dict2[key]:
match = False

You could compress this into a comprehension to just get the list of keys that don't match too:

mismatch_keys = [key for key in x if not key in y or x[key] != y[key]]
match = not bool(mismatch_keys) #If the list is not empty, they don't match
for key in mismatch_keys:
print key
print '%s -> %s' % (dict1[key],dict2[key])

The only other optimization I can think of might be to use "len(dict)" to figure out which dict has fewer entries and loop through that one first to have the shortest loop possible.

>>> a = {'x': 1, 'y': 2}
>>> b = {'y': 2, 'x': 1}
>>> print a == b
True
>>> c = {'z': 1}
>>> print a == c
False
>>>

Uhm, you are describing dict1 == dict2 ( check if boths dicts are equal )

But what your code does is all( dict1[k]==dict2[k] for k in dict1 ) ( check if all entries in dict1 are equal to those in dict2 )

If the dicts have identical sets of keys and you need all those prints for any value difference, there isn't much you can do; maybe something like:

diffkeys = [k for k in dict1 if dict1[k] != dict2[k]]
for k in diffkeys:
print k, ':', dict1[k], '->', dict2[k]

pretty much equivalent to what you have, but you might get nicer presentation for example by sorting diffkeys before you loop on it.

You can use sets for this too

>>> a = {'x': 1, 'y': 2}
>>> b = {'y': 2, 'x': 1}
>>> set(a.iteritems())-set(b.iteritems())
set([])
>>> a['y']=3
>>> set(a.iteritems())-set(b.iteritems())
set([('y', 3)])
>>> set(b.iteritems())-set(a.iteritems())
set([('y', 2)])
>>> set(b.iteritems())^set(a.iteritems())
set([('y', 3), ('y', 2)])

If the true intent of the question is the comparison between dicts (rather than printing differences), the answer is

dict1 == dict2

This has been mentioned before, but I felt it was slightly drowning in other bits of information. It might appear superficial, but the value comparison of dicts has actually powerful semantics. It covers

  • number of keys (if they don't match, the dicts are not equal)
  • names of keys (if they don't match, they're not equal)
  • value of each key (they have to be '==', too)

The last point again appears trivial, but is acutally interesting as it means that all of this applies recursively to nested dicts as well. E.g.

 m1 = {'f':True}
m2 = {'f':True}
m3 = {'a':1, 2:2, 3:m1}
m4 = {'a':1, 2:2, 3:m2}
m3 == m4  # True

Similar semantics exist for the comparison of lists. All of this makes it a no-brainer to e.g. compare deep Json structures, alone with a simple "==".

If your dictionaries are deeply nested and if they contain different types of collections, you could convert them to json string and compare.

import json
match = (json.dumps(dict1) == json.dumps(dict2))

caveat- this solution may not work if your dictionaries have binary strings in the values as this is not json serializable

Not sure if this helps but in my app I had to check if a dictionary has changed.

Doing this will not work since basically it's still the same object:

val={'A':1,'B':2}
old_val=val


val['A']=10
if old_val != val:
print('changed')

Using copy/deepcopy works:

import copy
val={'A':1,'B':2}
old_val=copy.deepcopy(val)


val['A']=10
if old_val != val:
print('changed')

If your values are hashable (ie. strings), then you can simply compare the ItemsView of the two dicts.

https://docs.python.org/3/library/stdtypes.html#dict-views

set_with_unique_key_value_pairs = dict1.items() ^ dict2.items()
set_with_matching_key_value_pairs = dict1.items() & dict2.items()

Any set operations are available to you.

Since you might not care about keys in this case, you can also just use the ValuesView (again, provided the values are hashable).

set_with_matching_values = dict1.values() & dict2.values()