Reputation: 389
I was watching a presentation and it introduced me to this way of finding the maximum value in a dictionary:
c = {"One":1, "Two":2, "Uns":1}
max(c,key=c.get)
'Two'
I don't understand quite how it works. The 'get' method returns the value for a key, if the key exists in the dictionary. So does the 'max' iterate through each key, find the associated value and then return the key associated with the maximum value? How does it work when the dictionary has multiple maximum values?
c = {"One":1, "Two":2, "Uns":1, "Dos": 2}
max(c,key=c.get)
'Dos'
To experiment further, I tried this:
c = {"One":1, "Two":2, "Uns":1}
max(c.values(),key=c.get)
1
Why did it return '1' instead of '2'?
Upvotes: 1
Views: 751
Reputation: 39960
When you call:
max(c, key=c.get)
the max
function internally iterates over the first parameter; for a dictionary this will iterate over the keys of the dictionary, in... some order, this is where things get hairy.
"One"
, "Two"
, "Uns"
, "Dos"
(See also the Python documentation on the dict
type.)
Now we know that the max()
function will see two possible keys that map to the maximum value, "Two"
and "Dos"
, in this order. The documentation for the max()
function states:
If multiple items are maximal, the function returns the first one encountered.
So in Python 3.7 as well as CPython 3.6, what is returned depends on the order in which the keys are inserted into the dictionary:
>>> c = {"Uns":1, "Dos":2, "One":1, "Two": 2}
>>> list(iter(c))
['Uns', 'Dos', 'One', 'Two']
>>> max(c, key=c.get)
'Dos'
>>> c = {"One":1, "Two":2, "Uns":1, "Dos": 2}
>>> list(iter(c))
['One', 'Two', 'Uns', 'Dos']
>>> max(c, key=c.get)
'Two'
In Python 3.5, which maximum will be the first encountered is arbitrary, but it will be the first key with a maximum value seen in list(iter(c))
In Python 2.7, the behaviour of the max()
function I cited above isn't specified in the documentation, so who knows really.
As for your second example, it really plain doesn't make sense, so I'll just rush past it: c.get()
will return None
when you pass it a key that doesn't exist in the dictionary. In Python 2.x, it was allowed to compare None
with None
using the <
operator that max()
uses to determine the maximum; I'm guessing since it compares two same objects, they were considered equal and thus the result of that comparison was False
, and every item in your case would be considered the "maximum". Since the order of the keys is unspecified in Python 2.x, and neither is which one is returned by max()
, the result you get is essentially arbitrary. Not that it matters, since there is no sense the whole thing could be making.
You could prevent this by avoiding the use of dict.get()
, and writing more assertive code that fails early because it's clear accessing a key that doesn't exist in the dictionary is a mistake:
max(c, key=lambda k: c[k])
Upvotes: 2
Reputation: 304255
Don't confuse the idea of the key of the dictionary, with the "key-function"
When two values are the same, max
or min
will return the first matching key. Since iteration of dict is unordered until Python3.6, it's not a good idea to rely on which particular key would be returned
In your last example, you are asking the dict to use the values as keys to the dict. This will usually return None
unless the value also happens to be a key (This will never happen if all the keys are str and all the values are int, for example). In Python2, since None
isn't greater than None
, the first key that is encountered will be the one that is eventually returned. In Python3, doing this comparison throws an exception.
Upvotes: 1