Adarsh Kumar
Adarsh Kumar

Reputation: 113

What do comparison operators do on dictionaries?

I came across this:

>>> d1 = {"john":40, "peter":45}
>>> d2 = {"john":466, "peter":45}
>>> d1 > d2
False

What does the comparison operator do while comparing two dicts and how does it output False?

Upvotes: 3

Views: 3548

Answers (3)

wim
wim

Reputation: 363043

Since these dicts have equal length, we find the smallest key for which the corresponding values are unequal, i.e. 'john'. Then the dicts are compared on the value of that key.

Demo:

>>> d1 = {"john":40, "peter":45}
>>> d2 = {"john":466, "peter":45}
>>> d1 < d2
True
>>> d2['john'] = 39
>>> d1 < d2
False

This basic idea is essentially unchanged since Guido's commit from over 20 years ago:

$ git show a0a69b8
commit a0a69b8b429f3d4c91f1c432247cfda017505976
Author: Guido van Rossum <[email protected]>
Date:   Thu Dec 5 21:55:55 1996 +0000

    Experimental new implementation of dictionary comparison.  This
    defines that a shorter dictionary is always smaller than a longer one.
    For dictionaries of the same size, the smallest differing element
    determines the outcome (which yields the same results as before,
    without explicit sorting).

It is not documented, and the dict comparison code is removed in Python 3, so I wouldn't rely on that for anything important. The relevant CPython source is here.

Fun fact: Apparently, in older versions of Python, some dict comparisons could crash the runtime and could even cause Windows 98 to reboot. Heh.

Upvotes: 8

void
void

Reputation: 2652

Dictionaries, like sets, do not maintain a well-defined order on their elements. Furthermore, the concept of a subset is not typically meaningful for dictionaries, so the dict class does not support operators such as < . Dictionaries support the notion of equivalence, with d1 == d2 if the two dictionaries contain the same set of key- value pairs.

So what you can do is,

d1 == d2  #d1 is equivalent to d2
d1 != d2  #d1 is not equivalent to d2

However you cannot do > < >= <=

This is in python 3.

>>> a
{1: '1', 2: '2'}
>>> b
{1: '1', 2: '2'}
>>> a==b
True
>>> a<b
Traceback (most recent call last):
  File "<pyshell#31>", line 1, in <module>
    a<b
TypeError: unorderable types: dict() < dict()
>>> a>b
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    a>b
TypeError: unorderable types: dict() > dict()
>>> 

However in python 2 take a look at this,

>>> a = {2:2}
>>> b = {2:2}
>>> a==b
True
>>> a<b
False
>>> a>b
False

But when the key is same and value is different

>>> a={3:1}
>>> b={3:2}
>>> a<b
True
>>> a>b
False

Again if value is same,

>>> a={3:0}
>>> b={3:0}
>>> a==b
True
>>> a<b
False
>>> a>b
False

But notice this when value in first dict is greater

>>> a={3:200}
>>> b={3:10}
>>> a<b
False
>>> a>b
True

Till now we had same key different values now let's change that,

Now Same value different key

>>> a={2:10}
>>> b={3:10}
>>> a<b
True
>>> a>b
False
>>> 
>>> a={10:10}
>>> b={1:10}
>>> a<b
False
>>> a>b
True

What can you get from this, Python 2 either key is checked and if it's same, only then ,value is checked. Now let's have different key , different values,

>>> a={10:10}
>>> b={1:100}
>>> a<b
False
>>> a>b
True

Aha! In this case you can infer that key is the first thing that will be checked and if they are the same only then value will be checked. Now let's say we have more than one key:value pair in our dictionary?

>>> a={10:10,1:10}
>>> b={10:10,2:10}
>>> a<b
True
>>> a>b
False
>>> a={10:10,200:10}
>>> b={10:10,1:10}
>>> a<b
False
>>> a>b
True

So it means. Every key is checked and then if key is same value will be checked. Ah but how does key checking work ? For that take a look at dict_compare source code

NOTE: The method cmp() returns the sign of the difference of two numbers : -1 if x < y, 0 if x == y, or 1 if x > y

So basically What happens is that to compare dicts A and B, lengths are compared first (equal no problem). If they are unequal, then return cmp(len(A), len(B)).

Next, find the key akey in A that is the smallest key for which

akey not in B or A[akey] != B[akey] -->(This happens only when akey is present in B).

(If there is no such key, the dicts are equal.)

Also (must) find the smallest key bkey in B for which

bkey not in A or A[bkey] != B[bkey] -->(This happens only when bkey is present in B).

If akey != bkey, then return cmp(akey, bkey). Else return cmp(A[akey], B[bkey])

>>> a={10:10,200:10}
>>> b={10:10,1:10}
>>> a<b
False
>>> a>b
True
>>> cmp(200,1)
1
>>> cmp(1,200)
-1

So the smallest key in A not in B is 200 similarly 1 in A.

Now internaly python compares them according to the given above algorithm so cmp(200,1) would be calculated when a>b is done. Else cmp(1,200) if a<b is done.

But this was removed completely from python 3. This doesn't work in python 3.

Upvotes: 2

Cenk
Cenk

Reputation: 11

>>> d2>d1
True
>>> d3 = {"john":40, "peter":45}
>>> d1>=d3
True

As you can see above, comparison on dictionaries done by key. These are equals;

>>> res = []
>>> for key1,val1 in d1.iteritems():
...     res.append(val1 >d2[key1] )
>>> res
[False, False]
>>> all(res)
False
>>> d1 > d2
False

Upvotes: -1

Related Questions