Obtenir une clé avec une valeur maximale dans le dictionnaire?
-
06-07-2019 - |
Question
J'ai un dictionnaire
: les clés sont des chaînes, les valeurs sont des entiers.
Exemple:
stats = {'a':1000, 'b':3000, 'c': 100}
Je voudrais obtenir 'b'
comme réponse, car c'est la clé avec la valeur la plus élevée.
J'ai fait ce qui suit en utilisant une liste intermédiaire avec des nuplets clé-valeur inversés:
inverse = [(value, key) for key, value in stats.items()]
print max(inverse)[1]
Cette approche est-elle la meilleure (ou même la plus élégante)? ??
La solution
Vous pouvez utiliser operator.itemgetter
pour cela:
import operator
stats = {'a':1000, 'b':3000, 'c': 100}
max(stats.iteritems(), key=operator.itemgetter(1))[0]
Et au lieu de construire une nouvelle liste en mémoire, utilisez stats.iteritems ()
. Le paramètre key
de la fonction max ()
est une fonction qui calcule une clé utilisée pour déterminer le classement des éléments.
Veuillez noter que si vous deviez disposer d'une autre paire clé-valeur 'd': 3000, cette méthode ne renverra que un des deux , bien qu'ils aient tous deux la valeur maximale.
>>> import operator
>>> stats = {'a':1000, 'b':3000, 'c': 100, 'd':3000}
>>> max(stats.iteritems(), key=operator.itemgetter(1))[0]
'b'
Si vous utilisez Python3:
>>> max(stats.items(), key=operator.itemgetter(1))[0]
'b'
Autres conseils
max(stats, key=stats.get)
J'ai testé DE NOMBREUSES variantes et c’est le moyen le plus rapide de renvoyer la clé de dict avec la valeur maximale:
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))]
Pour vous donner une idée, voici quelques méthodes candidates:
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)
Le dictionnaire de test:
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}
Et les résultats du test sous 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% --
Et sous 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% --
Vous pouvez voir que f1
est le plus rapide sous Python 3.2 et 2.7 (ou, plus complètement, keywithmaxval
en haut de ce billet)
Si vous avez besoin de connaître uniquement une clé avec la valeur maximale, vous pouvez le faire sans iterkeys
ou itéritems
car l'itération via le dictionnaire en Python est l'itération via ses clés.
max_key = max(stats, key=lambda k: stats[k])
EDIT:
À partir des commentaires, @ user1274878:
Je suis nouveau sur Python. Pouvez-vous expliquer votre réponse en plusieurs étapes?
Oui ...
max
max (itérable [, clé])
max (arg1, arg2, * args [, clé])
Renvoie le plus grand élément d'une variable itérable ou le plus grand de deux arguments ou plus.
L'argument facultatif key
décrit comment comparer des éléments pour obtenir le maximum entre eux:
lambda <item>: return <a result of operation with item>
Les valeurs renvoyées seront comparées.
Dict
Python dict est une table de hachage. Une clé de dict est le hachage d'un objet déclaré comme clé. Pour des raisons de performances, itération même si un dict est mis en oeuvre sous forme d'itération à travers ses clés.
Par conséquent, nous pouvons l’utiliser pour éviter d’obtenir une liste de clés.
Fermeture
Une fonction définie dans une autre fonction est appelée une fonction imbriquée. Les fonctions imbriquées peuvent accéder aux variables de la portée englobante.
La variable stats
disponible via l'attribut __ fermeture __
de la fonction lambda
en tant que pointeur sur la valeur de la variable définie dans la portée parente.
En voici un autre:
stats = {'a':1000, 'b':3000, 'c': 100}
max(stats.iterkeys(), key=lambda k: stats[k])
La fonction touche
renvoie simplement la valeur à utiliser pour le classement et max ()
renvoie immédiatement l'élément demandé.
key, value = max(stats.iteritems(), key=lambda x:x[1])
Si vous ne vous souciez pas de la valeur (je serais surpris, mais), vous pouvez faire:
key, _ = max(stats.iteritems(), key=lambda x:x[1])
J'aime mieux décomposer le tuple qu’un indice [0] à la fin de l’expression. Je n’aime jamais beaucoup la lisibilité des expressions lambda, mais je trouve celle-ci meilleure que celle de operator.itemgetter (1) IMHO.
Exemple:
stats = {'a':1000, 'b':3000, 'c': 100}
si vous voulez trouver la valeur maximale avec sa clé, suivez peut-être la suite, sans fonctions pertinentes.
max(stats, key=stats.get)
la sortie est la clé qui a la valeur max.
Étant donné que plusieurs entrées peuvent avoir la valeur maximale. Je voudrais faire une liste des clés qui ont la valeur max comme valeur.
>>> 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']
Cela vous donnera "b" ainsi que toute autre clé max.
Remarque: pour Python 3, utilisez stats.items ()
au lieu de stats.iteritems ()
Pour obtenir la clé / valeur maximale du dictionnaire stats
:
stats = {'a':1000, 'b':3000, 'c': 100}
- En fonction des touches
> > > max (stats.items (), clé = lambda x: x [0])
('c', 100)
- Basé sur des valeurs
> > > max (stats.items (), clé = lambda x: x [1])
('b', 3000)
Bien sûr, si vous souhaitez obtenir uniquement la clé ou la valeur du résultat, vous pouvez utiliser l’indexation par tuple. Par exemple, pour obtenir la clé correspondant à la valeur maximale:
> > > max (stats.items (), clé = lambda x: x [1]) [0]
'b'
Explication
La méthode du dictionnaire items ()
dans Python 3 renvoie un objet d'affichage de le dictionnaire. Lorsque cet objet de vue est itéré sur la fonction max
, il génère les éléments du dictionnaire sous forme de tuples de la forme (clé, valeur)
.
> > > liste (stats.items ())
[('c', 100), ('b', 3000), ('a', 1000)]
Lorsque vous utilisez le lambda
expression lambda x: x [1]
, à chaque itération, x
est l’un de ces uplets (clé, valeur)
. Ainsi, en choisissant le bon index, vous choisissez si vous souhaitez comparer les clés ou les valeurs.
Python 2
Pour les versions de Python 2.2+, le même code fonctionnera. Cependant, il est préférable d'utiliser iteritems ()
méthode de dictionnaire au lieu de items ()
pour la performance.
Notes
-
Cette réponse est basée sur les commentaires de la réponse de Climbs_lika_Spyder .
-
Le code utilisé a été testé sur Python 3.5.2 et 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')
Selon les solutions itérées via des commentaires dans la réponse sélectionnée ...
En Python 3:
max(stats.keys(), key=(lambda k: stats[k]))
En Python 2:
max(stats.iterkeys(), key=(lambda k: stats[k]))
Avec collections.Counter
, vous pouvez le faire
>>> import collections
>>> stats = {'a':1000, 'b':3000, 'c': 100}
>>> stats = collections.Counter(stats)
>>> stats.most_common(1)
[('b', 3000)]
Le cas échéant, vous pouvez simplement commencer par un collections.Counter
vide et y ajouter
>>> stats = collections.Counter()
>>> stats['a'] += 1
:
etc.
Je suis arrivé ici pour savoir comment retourner mydict.keys ()
en fonction de la valeur de mydict.values ??()
. Au lieu de la seule clé renvoyée, je cherchais à renvoyer le nombre x supérieur
Cette solution est plus simple que d'utiliser la fonction max ()
et vous pouvez facilement modifier le nombre de valeurs renvoyées:
stats = {'a':1000, 'b':3000, 'c': 100}
x = sorted(stats, key=(lambda key:stats[key]), reverse=True)
['b', 'a', 'c']
Si vous voulez la clé la plus haute, utilisez simplement l'index:
x[0]
['b']
Si vous voulez les deux clés les mieux classées, utilisez simplement le découpage en tranches:
x[:2]
['b', 'a']
Merci, très élégant, je ne me souvenais pas que max permettait une "clé". paramètre.
BTW, pour obtenir la bonne réponse ('b'), il doit être:
import operator
stats = {'a':1000, 'b':3000, 'c': 100}
max(stats.iteritems(), key=operator.itemgetter(1))[0]
max ((valeur, clé) pour la clé, valeur dans stats.items ()) [1]
Counter = 0
for word in stats.keys():
if stats[word]> counter:
Counter = stats [word]
print Counter
+1 à @Aric Coady Solution.
Et aussi une façon de sélectionner au hasard une des clés de valeur maximale dans le dictionnaire:
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])
Une file d'attente est une solution généralisée qui vous permet d'extraire les n clés supérieures, classées par valeur:
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'
Remarque dict .__ getitem __
est la méthode appelée par le sucre syntaxique dict []
. Contrairement à dict.get
, il retournera KeyError
si une clé n'est pas trouvée, ce qui ne peut pas se produire ici.
J'ai testé la réponse acceptée AND @ thewolf, la solution la plus rapide, par rapport à une boucle très basique et la boucle était plus rapide que les deux:
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))
résultats:
Iterating: 3.8201940059661865
List creating: 6.928712844848633
Accepted answer: 5.464320182800293
Que diriez-vous de:
max(zip(stats.keys(), stats.values()), key=lambda t : t[1])[0]