ChatGPT解决这个技术问题 Extra ChatGPT

Getting key with maximum value in dictionary?

I have a dictionary where keys are strings, and values are integers.

stats = {'a': 1, 'b': 3000, 'c': 0}

How do I get the key with the maximum value? In this case, it is 'b'.

Is there a nicer approach than using an intermediate list with reversed key-value tuples?

inverse = [(value, key) for key, value in stats.items()]
print(max(inverse)[1])
Um, what's wrong with max(stats)?
max(stats) will use the labels as keys (it will return 'c', given that's the maximum label), max(stats, key=lambda key: stats[key]) is what OP was after (which will return 'b', label of maximal indexed value). Is it any clearer?

A
A. Coady
max(stats, key=stats.get)

if you really wanted to do it this way you could do stats[max(stats, key=stats.get)]
@scottmrogowski, ss. It provides the key with the maximum value, as asked. The max value would be simply max(stats.values()).
This should be the answer as it is the simplest and was exactly what the OP asked for.
@Coady what if there is a tie between two keys (with the same value)? I want to get them both, but I get only one.
@oba2311 max_value = max(stats.values()); {key for key, value in stats.items() if value == max_value}
F
Francisco

You can use operator.itemgetter for that:

import operator
stats = {'a': 1000, 'b': 3000, 'c': 100}
max(stats.iteritems(), key=operator.itemgetter(1))[0]

And instead of building a new list in memory use stats.iteritems(). The key parameter to the max() function is a function that computes a key that is used to determine how to rank items.

Please note that if you were to have another key-value pair 'd': 3000 that this method will only return one of the two even though they both have the maximum value.

>>> import operator
>>> stats = {'a': 1000, 'b': 3000, 'c': 100, 'd': 3000}
>>> max(stats.iteritems(), key=operator.itemgetter(1))[0]
'b' 

If using Python3:

>>> max(stats.items(), key=operator.itemgetter(1))[0]
'b'

Even cleaner, I think= max(stats.iterkeys(), key=(lambda key: stats[key]))
Why not just use key=lambda x: x[1]?
in python 3 @Lucretiel's (correctly spelled) solution fails. it should be: max(stats.keys(), key=(lambda k: stats[k])) since keys() now does what iterkeys() used to do automatically.
Rigth you are. Interestingly, a solution that's exactly as memory efficient and works in both Python 2 and 3 is: max(stats, key=lambda key: stats[key])
Honestly I think that the comments have the cleaner and better solution.
F
Francisco

I have tested MANY variants, and this is the fastest way to return the key of dict with the max value:

def keywithmaxval(d):
     """ a) create a list of the dict's keys and values; 
         b) return the key with the max value"""  
     v = list(d.values())
     k = list(d.keys())
     return k[v.index(max(v))]

To give you an idea, here are some candidate methods:

def f1():  
     v = list(d1.values())
     k = list(d1.keys())
     return k[v.index(max(v))]
    
def f2():
    d3 = {v: k for k,v in d1.items()}
    return d3[max(d3)]
    
def f3():
    return list(filter(lambda t: t[1] == max(d1.values()), d1.items()))[0][0]    
    
def f3b():
    # same as f3 but remove the call to max from the lambda
    m = max(d1.values())
    return list(filter(lambda t: t[1] == m, d1.items()))[0][0]        
    
def f4():
    return [k for k, v in d1.items() if v == max(d1.values())][0]    
    
def f4b():
    # same as f4 but remove the max from the comprehension
    m = max(d1.values())
    return [k for k,v in d1.items() if v == m][0]        
    
def f5():
    return max(d1.items(), key=operator.itemgetter(1))[0]    
    
def f6():
    return max(d1, key=d1.get)     
    
def f7():
     """ a) create a list of the dict's keys and values; 
         b) return the key with the max value"""    
     v = list(d1.values())
     return list(d1.keys())[v.index(max(v))]    
     
def f8():
     return max(d1, key=lambda k: d1[k])     
     
tl = [f1, f2, f3b, f4b, f5, f6, f7, f8, f4, f3]     
cmpthese.cmpthese(tl, c=100) 

The test dictionary:

d1 = {1: 1, 2: 2, 3: 8, 4: 3, 5: 6, 6: 9, 7: 17, 8: 4, 9: 20, 10: 7, 11: 15, 
    12: 10, 13: 10, 14: 18, 15: 18, 16: 5, 17: 13, 18: 21, 19: 21, 20: 8, 
    21: 8, 22: 16, 23: 16, 24: 11, 25: 24, 26: 11, 27: 112, 28: 19, 29: 19, 
    30: 19, 3077: 36, 32: 6, 33: 27, 34: 14, 35: 14, 36: 22, 4102: 39, 38: 22, 
    39: 35, 40: 9, 41: 110, 42: 9, 43: 30, 44: 17, 45: 17, 46: 17, 47: 105, 48: 12, 
    49: 25, 50: 25, 51: 25, 52: 12, 53: 12, 54: 113, 1079: 50, 56: 20, 57: 33, 
    58: 20, 59: 33, 60: 20, 61: 20, 62: 108, 63: 108, 64: 7, 65: 28, 66: 28, 67: 28, 
    68: 15, 69: 15, 70: 15, 71: 103, 72: 23, 73: 116, 74: 23, 75: 15, 76: 23, 77: 23, 
    78: 36, 79: 36, 80: 10, 81: 23, 82: 111, 83: 111, 84: 10, 85: 10, 86: 31, 87: 31, 
    88: 18, 89: 31, 90: 18, 91: 93, 92: 18, 93: 18, 94: 106, 95: 106, 96: 13, 9232: 35, 
    98: 26, 99: 26, 100: 26, 101: 26, 103: 88, 104: 13, 106: 13, 107: 101, 1132: 63, 
    2158: 51, 112: 21, 113: 13, 116: 21, 118: 34, 119: 34, 7288: 45, 121: 96, 122: 21, 
    124: 109, 125: 109, 128: 8, 1154: 32, 131: 29, 134: 29, 136: 16, 137: 91, 140: 16, 
    142: 104, 143: 104, 146: 117, 148: 24, 149: 24, 152: 24, 154: 24, 155: 86, 160: 11, 
    161: 99, 1186: 76, 3238: 49, 167: 68, 170: 11, 172: 32, 175: 81, 178: 32, 179: 32, 
    182: 94, 184: 19, 31: 107, 188: 107, 190: 107, 196: 27, 197: 27, 202: 27, 206: 89, 
    208: 14, 214: 102, 215: 102, 220: 115, 37: 22, 224: 22, 226: 14, 232: 22, 233: 84, 
    238: 35, 242: 97, 244: 22, 250: 110, 251: 66, 1276: 58, 256: 9, 2308: 33, 262: 30, 
    263: 79, 268: 30, 269: 30, 274: 92, 1300: 27, 280: 17, 283: 61, 286: 105, 292: 118, 
    296: 25, 298: 25, 304: 25, 310: 87, 1336: 71, 319: 56, 322: 100, 323: 100, 325: 25, 
    55: 113, 334: 69, 340: 12, 1367: 40, 350: 82, 358: 33, 364: 95, 376: 108, 
    377: 64, 2429: 46, 394: 28, 395: 77, 404: 28, 412: 90, 1438: 53, 425: 59, 430: 103, 
    1456: 97, 433: 28, 445: 72, 448: 23, 466: 85, 479: 54, 484: 98, 485: 98, 488: 23, 
    6154: 37, 502: 67, 4616: 34, 526: 80, 538: 31, 566: 62, 3644: 44, 577: 31, 97: 119, 
    592: 26, 593: 75, 1619: 48, 638: 57, 646: 101, 650: 26, 110: 114, 668: 70, 2734: 41, 
    700: 83, 1732: 30, 719: 52, 728: 96, 754: 65, 1780: 74, 4858: 47, 130: 29, 790: 78, 
    1822: 43, 2051: 38, 808: 29, 850: 60, 866: 29, 890: 73, 911: 42, 958: 55, 970: 99, 
    976: 24, 166: 112}

And the test results under Python 3.2:

    rate/sec       f4      f3    f3b     f8     f5     f2    f4b     f6     f7     f1
f4       454       --   -2.5% -96.9% -97.5% -98.6% -98.6% -98.7% -98.7% -98.9% -99.0%
f3       466     2.6%      -- -96.8% -97.4% -98.6% -98.6% -98.6% -98.7% -98.9% -99.0%
f3b   14,715  3138.9% 3057.4%     -- -18.6% -55.5% -56.0% -56.4% -58.3% -63.8% -68.4%
f8    18,070  3877.3% 3777.3%  22.8%     -- -45.4% -45.9% -46.5% -48.8% -55.5% -61.2%
f5    33,091  7183.7% 7000.5% 124.9%  83.1%     --  -1.0%  -2.0%  -6.3% -18.6% -29.0%
f2    33,423  7256.8% 7071.8% 127.1%  85.0%   1.0%     --  -1.0%  -5.3% -17.7% -28.3%
f4b   33,762  7331.4% 7144.6% 129.4%  86.8%   2.0%   1.0%     --  -4.4% -16.9% -27.5%
f6    35,300  7669.8% 7474.4% 139.9%  95.4%   6.7%   5.6%   4.6%     -- -13.1% -24.2%
f7    40,631  8843.2% 8618.3% 176.1% 124.9%  22.8%  21.6%  20.3%  15.1%     -- -12.8%
f1    46,598 10156.7% 9898.8% 216.7% 157.9%  40.8%  39.4%  38.0%  32.0%  14.7%     --

And under Python 2.7:

    rate/sec       f3       f4     f8    f3b     f6     f5     f2    f4b     f7     f1
f3       384       --    -2.6% -97.1% -97.2% -97.9% -97.9% -98.0% -98.2% -98.5% -99.2%
f4       394     2.6%       -- -97.0% -97.2% -97.8% -97.9% -98.0% -98.1% -98.5% -99.1%
f8    13,079  3303.3%  3216.1%     --  -5.6% -28.6% -29.9% -32.8% -38.3% -49.7% -71.2%
f3b   13,852  3504.5%  3412.1%   5.9%     -- -24.4% -25.8% -28.9% -34.6% -46.7% -69.5%
f6    18,325  4668.4%  4546.2%  40.1%  32.3%     --  -1.8%  -5.9% -13.5% -29.5% -59.6%
f5    18,664  4756.5%  4632.0%  42.7%  34.7%   1.8%     --  -4.1% -11.9% -28.2% -58.8%
f2    19,470  4966.4%  4836.5%  48.9%  40.6%   6.2%   4.3%     --  -8.1% -25.1% -57.1%
f4b   21,187  5413.0%  5271.7%  62.0%  52.9%  15.6%  13.5%   8.8%     -- -18.5% -53.3%
f7    26,002  6665.8%  6492.4%  98.8%  87.7%  41.9%  39.3%  33.5%  22.7%     -- -42.7%
f1    45,354 11701.5% 11399.0% 246.8% 227.4% 147.5% 143.0% 132.9% 114.1%  74.4%     -- 

You can see that f1 is the fastest under Python 3.2 and 2.7 (or, more completely, keywithmaxval at the top of this post)


This seems fishy. f7 is like f1, just not giving a name to an intermediate object. f7 should be (very slightly) faster than f1, not much slower. And that's what I get: >>> timeit.timeit("f1()","from __main__ import f1, f7, d1", number=10000) 0.26785888786807277 >>> timeit.timeit("f7()","from __main__ import f1, f7, d1", number=10000) 0.26770628307832567
agree f1 is like f7. Did test with ipython %timeit and both came with same performance on my machine on python 2.7. Testing: f1 - 18 µs per loop Testing: f2 - 33.7 µs per loop Testing: f3b - 50 µs per loop Testing: f4b - 30.7 µs per loop Testing: f5 - 28 µs per loop Testing: f6 - 23 µs per loop Testing: f7 - 18 µs per loop Testing: f8 - 43.9 µs per loop Testing: f4 - 2.16 ms per loop Testing: f3 - 2.29 ms per loop
f1 is also applicable wherever max(d, key) is not available.
I thought dict is unsorted, couldn't d.keys and d.values theoretically be ordered differently?
The list-copy solutions are smelly to me. How's the performance on a dict with thousands or millions of entries?
p
pk786

You can use:

max(d, key = d.get) 
# which is equivalent to 
max(d, key = lambda k : d.get(k))

To return the key, value pair use:

max(d.items(), key = lambda k : k[1])

This should be the accepted answer, it's much simpler than using operator
What is the time complexity of this?
By far the best, answer: For explanation the d.items() creates a tuple and the lambda function uses a the value of the tuple as the object to evaluate, instead of the key.
this is the best/simples answer from all listed.
C
Community

If you need to know only a key with the max value you can do it without iterkeys or iteritems because iteration through dictionary in Python is iteration through it's keys.

max_key = max(stats, key=lambda k: stats[k])

EDIT:

From comments, @user1274878 :

I am new to python. Can you please explain your answer in steps?

Yep...

max

max(iterable[, key]) max(arg1, arg2, *args[, key]) Return the largest item in an iterable or the largest of two or more arguments.

The optional key argument describes how to compare elements to get maximum among them:

lambda <item>: return <a result of operation with item> 

Returned values will be compared.

Dict

Python dict is a hash table. A key of dict is a hash of an object declared as a key. Due to performance reasons iteration though a dict implemented as iteration through it's keys.

Therefore we can use it to rid operation of obtaining a keys list.

Closure

A function defined inside another function is called a nested function. Nested functions can access variables of the enclosing scope.

The stats variable available through __closure__ attribute of the lambda function as a pointer to the value of the variable defined in the parent scope.


@I159: I am new to python. Can you please explain your answer in steps
l
leo022

Example:

stats = {'a':1000, 'b':3000, 'c': 100}

if you wanna find the max value with its key, maybe follwing could be simple, without any relevant functions.

max(stats, key=stats.get)

the output is the key which has the max value.


this solution tested faster than max(stats, key=lambda key: stats[key])
u
user994998

Here is another one:

stats = {'a':1000, 'b':3000, 'c': 100}
max(stats.iterkeys(), key=lambda k: stats[k])

The function key simply returns the value that should be used for ranking and max() returns the demanded element right away.


.iterkeys is not needed in your answer (it's the default when iterating a dict). However, note that the .iteritems method fetches both key and value in one step, so there is no need for an extra getitem per key as needed with .iterkeys.
This is a great answer because it is very clear what's going on and is thus easy to extend to other situations.
in python3 version: max(stats, key=lambda k: stats[k])
D
Davoud Taghawi-Nejad
key, value = max(stats.iteritems(), key=lambda x:x[1])

If you don't care about value (I'd be surprised, but) you can do:

key, _ = max(stats.iteritems(), key=lambda x:x[1])

I like the tuple unpacking better than a [0] subscript at the end of the expression. I never like the readability of lambda expressions very much, but find this one better than the operator.itemgetter(1) IMHO.


_ could be used instead of ignored.
@J.F.Sebastian I agree ignored looks pretty ugly, but some people are against using _ for several reasons. I think the first snippet is fine even if you ignore the value
C
Climbs_lika_Spyder

Given that more than one entry my have the max value. I would make a list of the keys that have the max value as their value.

>>> stats = {'a':1000, 'b':3000, 'c': 100, 'd':3000}
>>> [key for m in [max(stats.values())] for key,val in stats.iteritems() if val == m]
['b', 'd']

This will give you 'b' and any other max key as well.

Note: For python 3 use stats.items() instead of stats.iteritems()


Your solution is OK but computes the maximum value as many times as there are items in the dict. If computing max were expensive (e.g., a LONG dictionary) I'd recommend [key for m in [max(stats.values())] for key,val in stats.iteritems() if val == m] if you want an one-liner, otherwise compute m = ... beforehand.
Just a short note: For python 3 use stats.items() instead of stats.iteritems().
P
Princy
max(stats, key=stats.get) if stats else None

stats could be an empty dictionary, so using only max(stats, key=stats.get) will break in that situation.


awesome answer! Simplest thing I could imagine.
Any idea what the time complexity of this is?
@RaGe Time complexity is O(n)
@Bhindi how did you know that time complexity of this is O(n)?
@NaourassDerouichi: You can verify the time complexity of max() function from here - wiki.python.org/moin/TimeComplexity
K
Karim Sonbol

To get the maximum key/value of the dictionary stats:

stats = {'a':1000, 'b':3000, 'c': 100}

Based on keys

>>> max(stats.items(), key = lambda x: x[0]) ('c', 100)

Based on values

>>> max(stats.items(), key = lambda x: x[1]) ('b', 3000)

Of course, if you want to get only the key or value from the result, you can use tuple indexing. For Example, to get the key corresponding to the maximum value:

>>> max(stats.items(), key = lambda x: x[1])[0] 'b'

Explanation

The dictionary method items() in Python 3 returns a view object of the dictionary. When this view object is iterated over, by the max function, it yields the dictionary items as tuples of the form (key, value).

>>> list(stats.items()) [('c', 100), ('b', 3000), ('a', 1000)]

When you use the lambda expression lambda x: x[1], in each iteration, x is one of these tuples (key, value). So, by choosing the right index, you select whether you want to compare by keys or by values.

Python 2

For Python 2.2+ releases, the same code will work. However, it is better to use iteritems() dictionary method instead of items() for performance.

Notes

This answer is based on the comments on Climbs_lika_Spyder's answer.

The used code was tested on Python 3.5.2 and Python 2.7.10 .


p
priya khokher
d = {'A': 4,'B':10}

min_v = min(zip(d.values(), d.keys()))
# min_v is (4,'A')

max_v = max(zip(d.values(), d.keys()))
# max_v is (10,'B')

k
kslote1

I was not satisfied with any of these answers. max always picks the first key with the max value. The dictionary could have multiple keys with that value.

def keys_with_top_values(my_dict):
    return [key  for (key, value) in my_dict.items() if value == max(my_dict.values())]

Posting this answer in case it helps someone out. See the below SO post

Which maximum does Python pick in the case of a tie?


This solution returns all the keys with the max value. max(stats, key=stats.get) only returns the first key it finds.
w
watsonic

Per the iterated solutions via comments in the selected answer...

In Python 3:

max(stats.keys(), key=(lambda k: stats[k]))

In Python 2:

max(stats.iterkeys(), key=(lambda k: stats[k]))

Your solution for Python 3 also works for Python 2.7.
because keys() does not return an iterator in python 2 and hence takes a performance hit
r
ron_g

I got here looking for how to return mydict.keys() based on the value of mydict.values(). Instead of just the one key returned, I was looking to return the top x number of values.

This solution is simpler than using the max() function and you can easily change the number of values returned:

stats = {'a':1000, 'b':3000, 'c': 100}

x = sorted(stats, key=(lambda key:stats[key]), reverse=True)
['b', 'a', 'c']

If you want the single highest ranking key, just use the index:

x[0]
['b']

If you want the top two highest ranking keys, just use list slicing:

x[:2]
['b', 'a']

This is a very inefficient solution. Sorting the dict will incur a runtime of n log (n) because you're concerning yourself with a bunch of values that are not the maximum. Using the max function will incur a runtime of just n which is much faster.
@PeterGraham pretty much every solution here (including the accepted answer) uses max(). It's clear it's the fastest. I thought I'd offer a different solution with the benefit of slicing, which was more useful to me at the time
A
Ali Sajjad

Much simpler to understand approach:

mydict = { 'a':302, 'e':53, 'g':302, 'h':100 }
max_value_keys = [key for key in mydict.keys() if mydict[key] == max(mydict.values())]
print(max_value_keys) # prints a list of keys with max value

Output: ['a', 'g']

Now you can choose only one key:

maximum = mydict[max_value_keys[0]]

u
ukrutt

With collections.Counter you could do

>>> import collections
>>> stats = {'a':1000, 'b':3000, 'c': 100}
>>> stats = collections.Counter(stats)
>>> stats.most_common(1)
[('b', 3000)]

If appropriate, you could simply start with an empty collections.Counter and add to it

>>> stats = collections.Counter()
>>> stats['a'] += 1
:
etc. 

j
jpp

A heap queue is a generalised solution which allows you to extract the top n keys ordered by value:

from heapq import nlargest

stats = {'a':1000, 'b':3000, 'c': 100}

res1 = nlargest(1, stats, key=stats.__getitem__)  # ['b']
res2 = nlargest(2, stats, key=stats.__getitem__)  # ['b', 'a']

res1_val = next(iter(res1))                       # 'b'

Note dict.__getitem__ is the method called by the syntactic sugar dict[]. As opposed to dict.get, it will return KeyError if a key is not found, which here cannot occur.


J
Jasha

max((value, key) for key, value in stats.items())[1]


This will order by the key with duplicate max values. That may or may not be desired.
A
Ashutosh

Following are two easy ways to extract key with max value from given dict

import time
stats = {
   "a" : 1000,
   "b" : 3000,
   "c" : 90,
   "d" : 74,
   "e" : 72,
 }

start_time = time.time_ns()
max_key = max(stats, key = stats.get)
print("Max Key [", max_key, "]Time taken (ns)", time.time_ns() - start_time)

start_time = time.time_ns()
max_key = max(stats, key=lambda key: stats[key])
print("Max Key with Lambda[", max_key, "]Time taken (ns)", time.time_ns() - start_time)

Output

Max Key [ b ] Time taken (ns) 3100
Max Key with Lambda [ b ] Time taken (ns) 1782

Solution with Lambda expression seems to be performing better for smaller inputs.


b
blueseal

+1 to @Aric Coady's simplest solution.
And also one way to random select one of keys with max value in the dictionary:

stats = {'a':1000, 'b':3000, 'c': 100, 'd':3000}

import random
maxV = max(stats.values())
# Choice is one of the keys with max value
choice = random.choice([key for key, value in stats.items() if value == maxV])

C
Corv Vette
Counter = 0
for word in stats.keys():
    if stats[word]> counter:
        Counter = stats [word]
print Counter

u
user2399453

How about:

 max(zip(stats.keys(), stats.values()), key=lambda t : t[1])[0]

zip(stats.keys(), stats.values()) is just a longer way to write stats.items(). Once you make that change, your answer will be almost identical to several older answers.
Agreed, I wasnt aware that items() is same as zip
items isn't the same as zip. It just produces the same result.
w
wkzhu

For scientific python users, here is a simple solution using Pandas:

import pandas as pd
stats = {'a': 1000, 'b': 3000, 'c': 100}
series = pd.Series(stats)
series.idxmax()

>>> b

S
Shaonsani

In case of stats is empty, one can check a condition before finding valued key like,

stats = {'a':1000, 'b':3000, 'c': 100}
max_key = None
if bool(stats):
   max_key = max(stats, key=stats.get)
print(max_key)

This can first check if the dictionary is empty or not, then process.

>>> b

B
BusBar_යසස්

Try this:

sorted(dict_name, key=dict_name.__getitem__, reverse=True)[0]

r
ragardner

I tested the accepted answer AND @thewolf's fastest solution against a very basic loop and the loop was faster than both:

import time
import operator


d = {"a"+str(i): i for i in range(1000000)}

def t1(dct):
    mx = float("-inf")
    key = None
    for k,v in dct.items():
        if v > mx:
            mx = v
            key = k
    return key

def t2(dct):
    v=list(dct.values())
    k=list(dct.keys())
    return k[v.index(max(v))]

def t3(dct):
    return max(dct.items(),key=operator.itemgetter(1))[0]

start = time.time()
for i in range(25):
    m = t1(d)
end = time.time()
print ("Iterating: "+str(end-start))

start = time.time()
for i in range(25):
    m = t2(d)
end = time.time()
print ("List creating: "+str(end-start))

start = time.time()
for i in range(25):
    m = t3(d)
end = time.time()
print ("Accepted answer: "+str(end-start))

results:

Iterating: 3.8201940059661865
List creating: 6.928712844848633
Accepted answer: 5.464320182800293

I
Ignacio Alorre

In the case you have more than one key with the same value, for example:

stats = {'a':1000, 'b':3000, 'c': 100, 'd':3000, 'e':3000}

You could get a collection with all the keys with max value as follow:

from collections import defaultdict
from collections import OrderedDict

groupedByValue = defaultdict(list)
for key, value in sorted(stats.items()):
    groupedByValue[value].append(key)

# {1000: ['a'], 3000: ['b', 'd', 'e'], 100: ['c']}

groupedByValue[max(groupedByValue)]
# ['b', 'd', 'e']

Good point! This solution is much easier: stackoverflow.com/a/47861776/10836415