Récupère la clé correspondant à la valeur minimale dans un dictionnaire

305

Si j'ai un dictionnaire Python, comment puis-je obtenir la clé de l'entrée qui contient la valeur minimale?

Je pensais à quelque chose à voir avec la min()fonction ...

Compte tenu de l'entrée:

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

Cela reviendrait 321.

tjvr
la source
Faute de frappe dans votre déclaration de retour? Sinon, pourquoi 321? Cela ne devrait-il pas être 320?
GreenMatt
3
@myself: D'accord, maintenant je vois - ce que l'on veut, c'est la clé de l'entrée où la valeur de l'entrée est le minimum. Une meilleure formulation de la question s'il vous plaît, car d'autres ont évidemment pensé la même chose que moi.
GreenMatt
2
Journée de sensibilisation à la structure des données: si vous interrogez (ou supprimez) uniquement l'élément minimal, envisagez d'utiliser une file d'attente ou un segment de priorité.
Colonel Panic

Réponses:

597

Le meilleur: min(d, key=d.get)- aucune raison d'interposer une lambdacouche d'indirection inutile ou d'extraire des éléments ou des clés!

Alex Martelli
la source
5
@ KarelBílek cela signifie que vous avez passé en "d" une liste par exemple [11, 22, 33], au lieu d'un dictionnaire par exemple {1: 11, 2:22, 3:33}. 'd.get' est valide pour un dictionnaire, mais pas pour une liste.
ToolmakerSteve
9
que faire si deux clés différentes ont la même valeur? et ils se trouvent être à la fois la plus petite valeur? comment pouvez-vous faire revenir les deux?
user3226932
5
Cette technique peut-elle être utilisée si les valeurs dict sont des listes, ex:, d={"a":[10, None], "b":[20, None]}où le min est calculé à partir de d [clé] [0]?
TrakJohnson
4
Comment cela marche-t-il? Quel genre de fonction min est que, je pensais que min () ne prenait que des valeurs individuelles ou des listes comme arguments. Comment fonctionne-t-il en boucle sur toutes les entrées du dictionnaire?
azureai
2
min()renvoie la valeur de la première valeur dans trié. clé désigne la façon de trier les valeurs. key=d.getsignifie que la liste sera triée selon les valeurs du dictionnaire.
notilas
45

Voici une réponse qui donne réellement la solution demandée par l'OP:

>>> 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)

d.iteritems()Cependant, l' utilisation sera plus efficace pour les dictionnaires plus volumineux.

Mark Rushakoff
la source
3
Au lieu du lambda, vous pouvez utiliser operator.itemgetter(1).
Philipp
2
à la place lamda utilise d.get
Texom512
Cela ne renvoie pas la clé comme demandé, mais la paire (clé, valeur).
Eric O Lebigot
14

Pour plusieurs clés qui ont la valeur la plus basse égale, vous pouvez utiliser une compréhension de liste:

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]

Une version fonctionnelle équivalente:

res = list(filter(lambda x: d[x]==minval, d))
jpp
la source
1
Votre réponse est très utile et d'autres sont probablement d'accord: voir les multiples commentaires d'ailleurs dans la réponse acceptée. Cependant, je devais revenir deux fois pour le trouver: envisageriez-vous de proposer une modification de la réponse acceptée? Le vôtre est en fait complémentaire.
jmon12
11

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

abyx
la source
6
>>> d = {320:1, 321:0, 322:3}
>>> min(d, key=lambda k: d[k]) 
321
Daniel Stutzbach
la source
@SilentGhost, @ blob8108: D'oh! Copiez-collez snafu. Fixé maintenant.
Daniel Stutzbach
Bonne solution je pense, mais la fonction anonyme n'ajoute qu'une couche d'indirection: key=d.getc'est mieux.
Eric O Lebigot
6

Dans le cas où vous avez plusieurs clés minimales et que vous souhaitez rester 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']
netskink
la source
4

Si vous n'êtes pas sûr de ne pas avoir plusieurs valeurs minimales, je suggère:

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
la source
3

Edit: c'est une réponse à la question originale de l'OP sur la clé minimale, pas la réponse minimale.


Vous pouvez obtenir les clés du dict en utilisant la keysfonction, et vous avez raison d'utiliser minpour trouver le minimum de cette liste.

Eli Bendersky
la source
Ne méritant pas vraiment un downvote, car la question originale de l'affiche n'était pas aussi claire qu'elle aurait pu l'être.
GreenMatt
@ Space_C0wb0y: peut-être pouvez-vous être si gentil de remarquer que le PO a modifié sa question pour signifier quelque chose de différent, après avoir répondu
Eli Bendersky
3

Une autre approche pour résoudre le problème de plusieurs clés avec la même valeur min:

>>> 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
la source
2

Utiliser minavec un itérateur (pour python 3 utiliser itemsau lieu de iteritems); au lieu de lambda, utilisez l' itemgetteropérateur from, qui est plus rapide que lambda.

from operator import itemgetter
min_key, _ = min(d.iteritems(), key=itemgetter(1))
Antti Haapala
la source
1
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]
aditya royal matturi
la source
Une idée de comment calculer la plus petite valeur AU-DESSUS de zéro?
Captain Anonymous
1

J'ai comparé les performances des trois options suivantes:

    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 )

Exemple de sortie:

#option 1
236230
0:00:14.136808

#option 2
236230
0:00:00.458026

#option 3
236230
0:00:00.824048
svinec
la source
0

pour créer une classe ordonnée, vous devez remplacer 6 fonctions spéciales, afin qu'elle soit appelée par la fonction min ()

ces méthodes sont __lt__ , __le__, __gt__, __ge__, __eq__ , __ne__dans l'ordre où elles sont inférieures, inférieures ou égales, supérieures à, supérieures ou égales, égales, non égales. par exemple, vous devez implémenter __lt__comme suit:

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

alors vous pouvez utiliser la fonction min comme suit:

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

cela a fonctionné pour moi.

Muhammad Korra
la source
0
min(zip(d.values(), d.keys()))[1]

Utilisez la fonction zip pour créer un itérateur de tuples contenant des valeurs et des clés. Enveloppez-le ensuite avec une fonction min qui prend le minimum en fonction de la première clé. Cela renvoie un tuple contenant une paire (valeur, clé). L'index de [1] est utilisé pour obtenir la clé correspondante

rajn
la source
2
Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant pourquoi et / ou comment ce code répond à la question améliore sa valeur à long terme.
β.εηοιτ.βε
@ β.εηοιτ.βε que mieux?
rajn
-1
# python 
d={320:1, 321:0, 322:3}
reduce(lambda x,y: x if d[x]<=d[y] else y, d.iterkeys())
  321
éruciforme
la source
6
1) Réduire est généralement plus lent que itertools. 2) La plupart des implémentations de réduire peuvent être faites plus simplement avec n'importe laquelle ou toutes. 3) Je suis un porte-parole géant pour le GvR. 4) Le module opérateur rend inutiles la plupart des lambdas simples, et les lambdas complexes doivent de toute façon être définis comme des fonctions réelles. J'ai peut-être juste peur de la programmation fonctionnelle. ;)
MikeD
@miked: dites m'en plus. qu'est-ce que gvr et quel est le module opérateur? pourriez-vous publier des liens? j'en connais peut-être d'autres, mais je ne suis qu'un intermédiaire en python. prêt à apprendre! :-)
eruciform
GvR est Guido van Rossum, le dictateur bienveillant de Python pour la vie. Voici un article de cinq ans de lui expliquant pourquoi les lisp-ismes (carte, filtre, réduction, lambda) n'ont pas beaucoup de place en python à l'avenir, et ces raisons sont toujours valables aujourd'hui. Le module opérateur a des remplacements pour extraire les membres : "lambda x: x [1]" par rapport à "itemgetter (1)" est un caractère plus long et prend sans doute plus de temps à comprendre. Je n'ai plus d'espace, mais posez des questions!
MikeD
@miked: vous voulez une première bouchée à la pomme? stackoverflow.com/questions/3292481/…
eruciform
Il n'est vraiment pas nécessaire de réimplémenter quelque chose de intégré ( min()).
Eric O Lebigot
-8

Est-ce ce que vous recherchez?

d = dict()
d[15.0]='fifteen'
d[14.0]='fourteen'
d[14.5]='fourteenandhalf'

print d[min(d.keys())]

Imprime «quatorze»

user365363
la source
8
-1: pas ce que la question demandait. Vous retournez la valeur avec la clé minimale, OP veut une clé avec la valeur minimale
Brian S