Получить ключ с максимальным значением в словаре?
У меня есть dictionary
: ключи - это строки, значения - целые числа.
Пример:
stats = {'a':1000, 'b':3000, 'c': 100}
Я хотел бы получить 'b'
как ответ, так как это ключ с более высоким значением.
Я сделал следующее, используя промежуточный список с обратными кортежами ключ-значение:
inverse = [(value, key) for key, value in stats.items()]
print max(inverse)[1]
Это лучший (или даже более элегантный) подход?
30 ответов
Ты можешь использовать operator.itemgetter
для этого:
import operator
stats = {'a':1000, 'b':3000, 'c': 100}
max(stats.iteritems(), key=operator.itemgetter(1))[0]
И вместо построения нового списка в памяти используйте stats.iteritems()
, key
параметр к max()
Функция - это функция, которая вычисляет ключ, который используется для определения порядка ранжирования элементов.
Обратите внимание, что если бы у вас была другая пара ключ-значение 'd': 3000, этот метод будет возвращать только один из двух, даже если они оба имеют максимальное значение.
>>> import operator
>>> stats = {'a':1000, 'b':3000, 'c': 100, 'd':3000}
>>> max(stats.iteritems(), key=operator.itemgetter(1))[0]
'b'
Если вы используете Python3:
>>> max(stats.items(), key=operator.itemgetter(1))[0]
'b'
Я протестировал МНОГИЕ варианты, и это самый быстрый способ вернуть ключ dict с максимальным значением:
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))]
Чтобы дать вам представление, вот несколько возможных методов:
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)
Тестовый словарь:
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}
И результаты теста под 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% --
И под 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% --
Ты это видишь f1
является самым быстрым в Python 3.2 и 2.7 (или, более полно, keywithmaxval
в верхней части этого поста)
Вы можете использовать:
max(d, key = d.get)
# which is equivalent to
max(d, key = lambda k : d.get(k))
Чтобы вернуть ключ, используйте пару значений:
max(d.items(), key = lambda k : k[1])
Если вам нужно знать только ключ с максимальным значением, вы можете сделать это без iterkeys
или же iteritems
потому что итерация по словарю в Python - это итерация по его ключам.
max_key = max(stats, key=lambda k: stats[k])
РЕДАКТИРОВАТЬ:
Из комментариев @user1274878:
Я новичок в питоне. Можете ли вы объяснить свой ответ в пошаговом режиме?
Ага...
Максимум
max(повторяемый [, ключ])
max(arg1, arg2, * args [, ключ])
Вернуть самый большой элемент в итерируемом или самый большой из двух или более аргументов.
Необязательный key
Аргумент описывает, как сравнивать элементы, чтобы получить максимум среди них:
lambda <item>: return <a result of operation with item>
Возвращенные значения будут сравниваться.
Dict
Python dict - это хеш-таблица. Ключ dict - это хеш объекта, объявленного как ключ. Из-за соображений производительности итерация, хотя dict реализована как итерация по ключам.
Поэтому мы можем использовать его для избавления от операции получения списка ключей.
закрытие
Функция, определенная внутри другой функции, называется вложенной функцией. Вложенные функции могут получать доступ к переменным окружения.
stats
переменная доступна через __closure__
атрибут lambda
функция как указатель на значение переменной, определенной в родительской области.
Пример:
stats = {'a':1000, 'b':3000, 'c': 100}
если вы хотите найти максимальное значение с помощью его ключа, возможно, последующие могут быть простыми, без каких-либо соответствующих функций.
max(stats, key=stats.get)
выход - это ключ, который имеет максимальное значение.
Вот еще один:
stats = {'a':1000, 'b':3000, 'c': 100}
max(stats.iterkeys(), key=lambda k: stats[k])
Функция key
просто возвращает значение, которое следует использовать для ранжирования и max()
возвращает требуемый элемент сразу.
key, value = max(stats.iteritems(), key=lambda x:x[1])
Если вас не волнует ценность (я бы удивился, но), вы можете сделать:
key, _ = max(stats.iteritems(), key=lambda x:x[1])
Мне нравится распаковка кортежей лучше, чем индекс [0] в конце выражения. Мне никогда не нравилась читаемость лямбда-выражений, но я нашел это лучше, чем operator.itemgetter(1) IMHO.
max(stats, key=stats.get) if stats else None
статистика также может быть пустым словарем и max(stats, key=stats.get)
сломается в этой ситуации.
Учитывая, что более одной записи могут иметь максимальное значение. Я бы сделал список ключей, которые имеют максимальное значение в качестве значения.
>>> 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']
Это даст вам 'b' и любой другой ключ макс.
Примечание: для Python 3 используйте stats.items()
вместо stats.iteritems()
Чтобы получить максимальный ключ / значение словаря stats
:
stats = {'a':1000, 'b':3000, 'c': 100}
- На основе ключей
>>> max(stats.items(), key = lambda x: x[0])
('c', 100)
- На основании значений
>>> max(stats.items(), key = lambda x: x[1])
('b', 3000)
Конечно, если вы хотите получить только ключ или значение из результата, вы можете использовать индексирование кортежей. Например, чтобы получить ключ, соответствующий максимальному значению:
>>> max(stats.items(), key = lambda x: x[1])[0]
'b'
объяснение
Словарь метод items()
в Python 3 возвращает вид объекта словаря. Когда этот объект просмотра повторяется, max
функция, она возвращает элементы словаря как кортежи вида (key, value)
,
>>> list(stats.items())
[('c', 100), ('b', 3000), ('a', 1000)]
Когда вы используете lambda
выражение lambda x: x[1]
в каждой итерации x
один из этих кортежей (key, value)
, Таким образом, выбирая правильный индекс, вы выбираете, хотите ли вы сравнить по ключам или по значениям.
Python 2
Для версий Python 2.2+ будет работать тот же код. Тем не менее, лучше использовать iteritems()
словарный метод вместо items()
для исполнения.
Заметки
Этот ответ основан на комментариях к ответу Climbs_lika_Spyder.
Использованный код был протестирован на Python 3.5.2 и Python 2.7.10 .
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')
Ни один из этих ответов меня не удовлетворил. max
всегда выбирает первый ключ с максимальным значением. В словаре может быть несколько ключей с этим значением.
def keys_with_top_values(my_dict):
return [key for (key, value) in my_dict.items() if value == max(my_dict.values())]
Отправка этого ответа на случай, если он кому-то поможет. См. Ниже сообщение SO
За повторные решения через комментарии в выбранном ответе...
В Python 3:
max(stats.keys(), key=(lambda k: stats[k]))
В Python 2:
max(stats.iterkeys(), key=(lambda k: stats[k]))
Я пришел сюда в поисках как вернуться mydict.keys()
основанный на значении mydict.values()
, Вместо того, чтобы возвращать только один ключ, я искал, чтобы вернуть верхнее число значений.
Это решение проще, чем использование max()
функция, и вы можете легко изменить количество возвращаемых значений:
stats = {'a':1000, 'b':3000, 'c': 100}
x = sorted(stats, key=(lambda key:stats[key]), reverse=True)
['b', 'a', 'c']
Если вам нужен единственный ключ с самым высоким рейтингом, просто используйте индекс:
x[0]
['b']
Если вы хотите получить два верхних ключа с самым высоким рейтингом, просто используйте нарезку списка:
x[:2]
['b', 'a']
С collections.Counter
ты мог бы сделать
>>> import collections
>>> stats = {'a':1000, 'b':3000, 'c': 100}
>>> stats = collections.Counter(stats)
>>> stats.most_common(1)
[('b', 3000)]
Если уместно, вы можете просто начать с пустого collections.Counter
и добавить к этому
>>> stats = collections.Counter()
>>> stats['a'] += 1
:
etc.
Намного более простой для понимания подход:
dict = { 'a':302, 'e':53, 'g':302, 'h':100 }
max_value_keys = [key for key in dict.keys() if dict[key] == max(dict.values())]
print(max_value_keys) # prints a list of keys with max value
Вывод: ['a', 'g']
Теперь вы можете выбрать только один ключ:
maximum = dict[max_value_keys[0]]
Очередь кучи - это обобщенное решение, которое позволяет извлекать верхние n ключей, упорядоченные по значению:
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'
Заметка dict.__getitem__
метод, вызываемый синтаксическим сахаром dict[]
, В отличие от dict.get
, он вернется KeyError
если ключ не найден, чего здесь не может быть.
Ниже приведены два простых способа извлечь ключ с максимальным значением из заданного 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)
Выход
Max Key [ b ] Time taken (ns) 3100
Max Key with Lambda [ b ] Time taken (ns) 1782
Решение с лямбда-выражением кажется лучше для небольших входных данных.
Для научных пользователей Python есть простое решение с использованием Pandas:
import pandas as pd
stats = {'a': 1000, 'b': 3000, 'c': 100}
series = pd.Series(stats)
series.idxmax()
>>> b
Спасибо, очень элегантно, я не помню, чтобы max разрешил параметр "ключ".
Кстати, чтобы получить правильный ответ ('b'), это должно быть:
import operator
stats = {'a':1000, 'b':3000, 'c': 100}
max(stats.iteritems(), key=operator.itemgetter(1))[0]
+1 к простейшему решению @Aric Coady.
А также один из способов случайного выбора одного из ключей с максимальным значением в словаре:
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])
Как насчет:
max(zip(stats.keys(), stats.values()), key=lambda t : t[1])[0]
Если статистика пуста, можно проверить условие, прежде чем найти значимый ключ, например,
stats = {'a':1000, 'b':3000, 'c': 100}
max_key = None
if bool(stats):
max_key = max(stats, key=stats.get)
print(max_key)
Это может сначала проверить, пустой словарь или нет, а затем обработать.
>>> b
Counter = 0
for word in stats.keys():
if stats[word]> counter:
Counter = stats [word]
print Counter
Попробуй это:
sorted(dict_name, key=dict_name.__getitem__, reverse=True)[0]
Просто добавьте ситуацию, когда вы хотите выбрать определенные клавиши вместо всех:
stats = {'a':1000, 'b':3000, 'c': 100, 'd':3000, 'e':3000}
keys_to_search = ["a", "b", "c"]
max([k for k in keys_to_search], key=lambda x: stats[x])```
Если у вас есть несколько ключей с одинаковым значением, например:
stats = {'a':1000, 'b':3000, 'c': 100, 'd':3000, 'e':3000}
Вы можете получить коллекцию со всеми ключами с максимальным значением следующим образом:
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']
Я проверил принятый ответ и самое быстрое решение AND @thewolf с очень простым циклом, и цикл был быстрее, чем оба:
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))
Результаты:
Iterating: 3.8201940059661865
List creating: 6.928712844848633
Accepted answer: 5.464320182800293