451

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.

gyre
  • 16,369
  • 3
  • 37
  • 47
tjvr
  • 17,431
  • 6
  • 25
  • 26
  • 9
    Data structure awareness day: if you only ever query (or remove) the minimum element, consider using a priority queue or heap. – Colonel Panic Oct 22 '13 at 13:43
  • 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? – heretoinfinity Aug 30 '21 at 00:17

17 Answers17

922

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
Intrastellar Explorer
  • 3,005
  • 9
  • 52
  • 119
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 2
    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? – Beni Cherniavsky-Paskin Sep 18 '11 at 16:12
  • What is the running time of this solution? – Kien Nguyen Jan 13 '13 at 17:57
  • `AttributeError: 'list' object has no attribute 'get'` - what does that mean, dammit? – Karel Bílek Jul 30 '13 at 15:07
  • 5
    @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. – ToolmakerSteve Dec 08 '13 at 02:31
  • 14
    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? – user3226932 Dec 18 '16 at 04:29
  • 7
    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] ? – TrakJohnson Dec 31 '16 at 17:36
  • 10
    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? – azureai Mar 14 '17 at 15:10
  • And what is d? The name of the dictionary? – azureai Mar 14 '17 at 16:14
  • @azureai yes it is – Captain Anonymous Jun 25 '17 at 14:50
  • 11
    `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. – notilas Jun 06 '18 at 06:54
  • 3
    It's easy to get the lowest/highest values but how can we get two or more lowest/highest values? – astroluv Oct 15 '18 at 16:38
  • what do you mean by "no reason to interpose a useless lambda"? – JUNPA Jan 31 '19 at 07:50
  • 1
    How can we find 2 min values or key of 2 min values? – Piyush S. Wanare Apr 13 '19 at 18:23
  • 1
    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. – jmon12 Apr 20 '20 at 15:04
  • 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. – Carnifex May 06 '20 at 09:12
  • 2
    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__` – khuang834 Mar 11 '22 at 06:13
79

Here's an answer that actually gives the solution the OP asked for:

>>> d = {320:1, 321:0, 322:3}
>>> d.items()
[(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)

Using d.iteritems() will be more efficient for larger dictionaries, however.

Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
55

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))
jpp
  • 159,742
  • 34
  • 281
  • 339
  • 4
    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. – jmon12 Apr 20 '20 at 15:03
14

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

abyx
  • 69,862
  • 18
  • 95
  • 117
8
>>> d = {320:1, 321:0, 322:3}
>>> min(d, key=lambda k: d[k]) 
321
Daniel Stutzbach
  • 74,198
  • 17
  • 88
  • 77
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']
Elias Zamaria
  • 96,623
  • 33
  • 114
  • 148
netskink
  • 4,033
  • 2
  • 34
  • 46
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
turtle_in_mind
  • 986
  • 1
  • 18
  • 36
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
perimosocordiae
  • 17,287
  • 14
  • 60
  • 76
  • Not really deserving a downvote, as the poster's original question wasn't as clear as it might have been. – GreenMatt Jul 19 '10 at 16:30
  • @Space_C0wb0y: perhaps you can be so kind to notice that the OP edited his question to mean something different, after I answered – Eli Bendersky Jul 19 '10 at 16:40
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
"""
Tony Veijalainen
  • 5,447
  • 23
  • 31
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]
PaulMcG
  • 62,419
  • 16
  • 94
  • 130
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))
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]
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
svinec
  • 679
  • 8
  • 9
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
2

Or __getitem__:

>>> d = {320: 1, 321: 0, 322: 3}
>>> min(d, key=d.__getitem__)
321
U13-Forward
  • 69,221
  • 14
  • 89
  • 114
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.
-1
# python 
d={320:1, 321:0, 322:3}
reduce(lambda x,y: x if d[x]<=d[y] else y, d.iterkeys())
  321
eruciform
  • 7,680
  • 1
  • 35
  • 47
  • 6
    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. ;) – MikeD Jul 20 '10 at 14:30
  • @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! :-) – eruciform Jul 20 '10 at 15:35
  • GvR is Guido van Rossum, Python's benevolent dictator for life. Here's a [five year old post](http://www.artima.com/weblogs/viewpost.jsp?thread=98196) 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](http://docs.python.org/library/operator.html#operator.attrgetter): "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! – MikeD Jul 20 '10 at 16:17
  • @miked: want first bite at the apple? http://stackoverflow.com/questions/3292481/most-important-python-optimizations – eruciform Jul 20 '10 at 17:08
  • Their is really no need to reimplement something built in (`min()`). – Eric O. Lebigot Apr 06 '17 at 10:16