Get the key corresponding to the minimum value within a dictionary
Asked Answered
U

17

467

If I have a Python dictionary, how do I get the key to the entry which contains the minimum value?

I was thinking about something to do with the min() function...

Given the input:

{320:1, 321:0, 322:3}

It would return 321.

Ursel answered 19/7, 2010 at 16:11 Comment(2)
Data structure awareness day: if you only ever query (or remove) the minimum element, consider using a priority queue or heap.Helico
What if you had to traverse a list to form the dictionary? Would you still consider using a priority queue as you still have to deal with O(n) time to read the list?Matrass
R
949

Best: min(d, key=d.get) -- no reason to interpose a useless lambda indirection layer or extract items or keys!

>>> d = {320: 1, 321: 0, 322: 3}
>>> min(d, key=d.get)
321
Rhyner answered 19/7, 2010 at 16:11 Comment(16)
I'm tempted to write min(d.keys(), key=d.get) to clarify this returns one of the keys to the reader; but in 2.x .keys() is wasteful (and .iterkeys() just muddies the picture). What do you think?Chaim
What is the running time of this solution?Pillowcase
AttributeError: 'list' object has no attribute 'get' - what does that mean, dammit?Sketchy
@KarelBílek it means you passed in as "d" a list e.g. [11, 22, 33], instead of a dictionary e.g. {1: 11, 2:22, 3:33}. 'd.get' is valid for a dictionary, but not for a list.Loach
what if two different keys have the same value? and they happen to both be the smallest value? how can you make it return both?Polymyxin
Can this technique be used if the dict values are lists, ex: d={"a":[10, None], "b":[20, None]}, where the min is calculated from d[key][0] ?Foreigner
How does this work? What kind of min function is that, I thought min() only took either individual values or lists as arguments. How does it loop over all the entries in the dictionary?Dirndl
And what is d? The name of the dictionary?Dirndl
@Dirndl yes it isFlorindaflorine
min() return the value in the first value in sorted. key designate the way to sort the values. key=d.get means the list will be sorted by values of the dictionary.Mcsweeney
It's easy to get the lowest/highest values but how can we get two or more lowest/highest values?Alwin
what do you mean by "no reason to interpose a useless lambda"?Arch
How can we find 2 min values or key of 2 min values?Tug
That's maybe worth to point out that it will only work for dictionaries (or containers having a get member function). For a more generic version, the lambda indirection would actually be necessary.Citronellal
lambda is not entirely useless in such cases. Admitted that for this specific question your answer is the best. But in practise one also often needs the value that belongs to that key.Negrophobe
Keep in mind that using d.get you'll lose the typing information from d. In more recent mypy (e.g. >0.9.3.1), you'll get a type error. To preserve typing information, use d.__getitem__Sinuate
M
80

This returns the key, value pair tuple after comparing values:

>>> d = {320:1, 321:0, 322:3}
>>> d.items()
dict_items([(320, 1), (321, 0), (322, 3)])  # Python 2.7 [(320, 1), (321, 0), (322, 3)]
>>> # find the minimum by comparing the second element of each tuple
>>> min(d.items(), key=lambda x: x[1]) 
(321, 0)

For Python 2.7, use d.iteritems() for larger dictionaries as it avoid copying. Python 3's dict.items() is already an itemview so no changes need.

Marciano answered 19/7, 2010 at 16:11 Comment(6)
Instead of the lambda you can use operator.itemgetter(1).Kant
instead lamda use d.getElastomer
This does not return the key as asked, but the (key, value) pair.Janae
Note that dict.iteritems() is no longer supported as at python 3.0. docs.python.org/3/library/stdtypes.html#dict.iteritemsBursarial
@Bursarial More like dict.iteritems became dict.items.Boondoggle
@Elastomer d.get won't work with d.items(), it'll work with just d; won't help when you want the key-value pair result.Trustworthy
G
56

For multiple keys which have equal lowest value, you can use a list comprehension:

d = {320:1, 321:0, 322:3, 323:0}

minval = min(d.values())
res = [k for k, v in d.items() if v==minval]

[321, 323]

An equivalent functional version:

res = list(filter(lambda x: d[x]==minval, d))
Grados answered 19/7, 2010 at 16:11 Comment(1)
Your answer is very useful and others probably agree: see the multiple comments for that matter in the accepted answer. However, I needed to come back twice to find it: would you consider proposing an edit to the accepted answer? Yours is actually complementary.Citronellal
P
14

min(d.items(), key=lambda x: x[1])[0]

Phelgon answered 19/7, 2010 at 16:11 Comment(0)
P
8

For the case where you have multiple minimal keys and want to keep it simple

def minimums(some_dict):
    positions = [] # output variable
    min_value = float("inf")
    for k, v in some_dict.items():
        if v == min_value:
            positions.append(k)
        if v < min_value:
            min_value = v
            positions = [] # output variable
            positions.append(k)

    return positions

minimums({'a':1, 'b':2, 'c':-1, 'd':0, 'e':-1})

['e', 'c']
Plutus answered 19/7, 2010 at 16:11 Comment(0)
A
8
>>> d = {320:1, 321:0, 322:3}
>>> min(d, key=lambda k: d[k]) 
321
Akbar answered 19/7, 2010 at 16:11 Comment(2)
@SilentGhost, @blob8108: D'oh! Copy-and-paste snafu. Fixed now.Akbar
Fine solution I think, but the anonymous function only adds a layer of indirection: key=d.get is better.Janae
T
7
min(zip(d.values(), d.keys()))[1]

Use the zip function to create an iterator of tuples containing values and keys. Then wrap it with a min function which takes the minimum based on the first key. This returns a tuple containing (value, key) pair. The index of [1] is used to get the corresponding key.

Twirp answered 19/7, 2010 at 16:11 Comment(2)
While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.Leek
@β.εηοιτ.βε that better?Closing
C
4

Another approach to addressing the issue of multiple keys with the same min value:

>>> dd = {320:1, 321:0, 322:3, 323:0}
>>>
>>> from itertools import groupby
>>> from operator import itemgetter
>>>
>>> print [v for k,v in groupby(sorted((v,k) for k,v in dd.iteritems()), key=itemgetter(0)).next()[1]]
[321, 323]
Cyruscyst answered 19/7, 2010 at 16:11 Comment(0)
H
4

If you are not sure that you have not multiple minimum values, I would suggest:

d = {320:1, 321:0, 322:3, 323:0}
print ', '.join(str(key) for min_value in (min(d.values()),) for key in d if d[key]==min_value)

"""Output:
321, 323
"""
Hylton answered 19/7, 2010 at 16:11 Comment(0)
W
4

You can get the keys of the dict using the keys function, and you're right about using min to find the minimum of that list.

This is an answer to the OP's original question about the minimal key, not the minimal answer.

Worshipful answered 19/7, 2010 at 16:11 Comment(2)
Not really deserving a downvote, as the poster's original question wasn't as clear as it might have been.Jambeau
@Space_C0wb0y: perhaps you can be so kind to notice that the OP edited his question to mean something different, after I answeredWorshipful
H
2

Or __getitem__:

>>> d = {320: 1, 321: 0, 322: 3}
>>> min(d, key=d.__getitem__)
321
Hexachlorophene answered 19/7, 2010 at 16:11 Comment(0)
D
2

To create an orderable class you have to override six special functions, so that it would be called by the min() function.

These methods are__lt__ , __le__, __gt__, __ge__, __eq__ , __ne__ in order they are less than, less than or equal, greater than, greater than or equal, equal, not equal.

For example, you should implement __lt__ as follows:

def __lt__(self, other):
  return self.comparable_value < other.comparable_value

Then you can use the min function as follows:

minValue = min(yourList, key=(lambda k: yourList[k]))

This worked for me.

Discipline answered 19/7, 2010 at 16:11 Comment(0)
C
2

I compared how the following three options perform:

    import random, datetime

myDict = {}
for i in range( 10000000 ):
    myDict[ i ] = random.randint( 0, 10000000 )



# OPTION 1

start = datetime.datetime.now()

sorted = []
for i in myDict:
    sorted.append( ( i, myDict[ i ] ) )
sorted.sort( key = lambda x: x[1] )
print( sorted[0][0] )

end = datetime.datetime.now()
print( end - start )



# OPTION 2

start = datetime.datetime.now()

myDict_values = list( myDict.values() )
myDict_keys = list( myDict.keys() )
min_value = min( myDict_values )
print( myDict_keys[ myDict_values.index( min_value ) ] )

end = datetime.datetime.now()
print( end - start )



# OPTION 3

start = datetime.datetime.now()

print( min( myDict, key=myDict.get ) )

end = datetime.datetime.now()
print( end - start )

Sample output:

#option 1
236230
0:00:14.136808

#option 2
236230
0:00:00.458026

#option 3
236230
0:00:00.824048
Comedo answered 19/7, 2010 at 16:11 Comment(0)
C
2
d={}
d[320]=1
d[321]=0
d[322]=3
value = min(d.values())
for k in d.keys(): 
    if d[k] == value:
        print k,d[k]
Conventioneer answered 19/7, 2010 at 16:11 Comment(1)
Any idea how to work out the smallest value ABOVE zero?Florindaflorine
R
2

Use min with an iterator (for python 3 use items instead of iteritems); instead of lambda use the itemgetter from operator, which is faster than lambda.

from operator import itemgetter
min_key, _ = min(d.iteritems(), key=itemgetter(1))
Rap answered 19/7, 2010 at 16:11 Comment(0)
S
0
my_dic = {320:1, 321:0, 322:3}
min_value = sorted(my_dic, key=lambda k: my_dic[k])[0]
print(min_value)

A solution with only the sorted method.

  1. I sorted values from smallest to largest with sorted method
  2. When we get the first index, it gives the smallest key.
Sanguinolent answered 19/7, 2010 at 16:11 Comment(0)
D
-1
# python 
d={320:1, 321:0, 322:3}
reduce(lambda x,y: x if d[x]<=d[y] else y, d.iterkeys())
  321
Dynatron answered 19/7, 2010 at 16:11 Comment(5)
1)Reduce is generally slower than itertools. 2)Most implementations of reduce can be done simpler with any or all. 3)I am a giant mouthpiece for GvR. 4)The operator module makes most simple lambdas unnecessary, and complex lambdas should be defined as real functions anyway. Maybe I'm just scared of functional programming. ;)Inimical
@miked: tell me more. what's gvr and what's the operator module? could you post links? i may know others, but i'm still just an intermediate in python. willing to learn! :-)Dynatron
GvR is Guido van Rossum, Python's benevolent dictator for life. Here's a five year old post from him explaining why lisp-isms (map,filter,reduce,lambda) don't have much of a place in python going forward, and those reasons are still true today. The operator module has replacements for extracting members: "lambda x: x[1]" compared to "itemgetter(1)" is a character longer and arguably takes longer to understand. I'm out of space, but ask questions!Inimical
@miked: want first bite at the apple? #3292981Dynatron
Their is really no need to reimplement something built in (min()).Janae

© 2022 - 2024 — McMap. All rights reserved.