Ottieni la chiave corrispondente al valore minimo all'interno di un dizionario


305

Se ho un dizionario Python, come posso ottenere la chiave per la voce che contiene il valore minimo?

Stavo pensando a qualcosa a che fare con la min()funzione ...

Dato l'input:

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

Sarebbe tornato 321.


Errore di battitura nel reso dichiarato? Altrimenti, perché 321? Non dovrebbe essere 320?
GreenMatt,

3
@myself: Okay, ora vedo - ciò che si desidera è la chiave della voce in cui il valore della voce è il minimo. Formulazione migliore per la domanda, per favore, come altri ovviamente hanno pensato lo stesso di me.
GreenMatt,

2
Giornata di sensibilizzazione sulla struttura dei dati: se si esegue solo la query (o la rimozione) dell'elemento minimo, considerare l'utilizzo di una coda o heap prioritario.
Colonnello Panic,

Risposte:


597

Meglio: min(d, key=d.get)- nessun motivo per interporre uno lambdastrato indiretto inutile o estrarre elementi o chiavi!


5
@ KarelBílek significa che hai inserito come "d" un elenco [11, 22, 33], ad esempio , anziché un dizionario, ad esempio {1: 11, 2:22, 3:33}. 'd.get' è valido per un dizionario, ma non per un elenco.
ToolmakerSteve

9
cosa succede se due chiavi diverse hanno lo stesso valore? e capita di essere entrambi il valore più piccolo? come puoi farlo restituire entrambi?
user3226932

5
Questa tecnica può essere utilizzata se i valori di dict sono elenchi, ad es. d={"a":[10, None], "b":[20, None]}, In cui il min è calcolato da d [chiave] [0]?
Trak Johnson,

4
Come funziona? Che tipo di funzione min è quella, ho pensato che min () prendesse solo argomenti individuali o liste come argomenti. Come fa a scorrere su tutte le voci nel dizionario?
Azureai,

2
min()restituisce il valore nel primo valore in ordinato. chiave indica il modo di ordinare i valori. key=d.getindica che l'elenco verrà ordinato in base ai valori del dizionario.
notilas,

45

Ecco una risposta che fornisce effettivamente la soluzione richiesta dall'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)

L'uso d.iteritems()sarà più efficiente per dizionari più grandi, tuttavia.


3
Invece della lambda puoi usare operator.itemgetter(1).
Philipp,

2
invece lamda usa d.get
Texom512,

Questo non restituisce la chiave come richiesto, ma la coppia (chiave, valore).
Eric O Lebigot,

14

Per più chiavi che hanno lo stesso valore più basso, è possibile utilizzare una comprensione dell'elenco:

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]

Una versione funzionale equivalente:

res = list(filter(lambda x: d[x]==minval, d))

1
La tua risposta è molto utile e altri probabilmente sono d'accordo: vedi i commenti multipli per quella materia nella risposta accettata. Tuttavia, ho dovuto tornare due volte per trovarlo: valuteresti di proporre una modifica alla risposta accettata? Il tuo è in realtà complementare.
jmon12,


6
>>> d = {320:1, 321:0, 322:3}
>>> min(d, key=lambda k: d[k]) 
321

@SilentGhost, @ blob8108: D'oh! Copia e incolla snafu. Riparato ora.
Daniel Stutzbach,

Ottima soluzione, penso, ma la funzione anonima aggiunge solo uno strato di indiretta: key=d.getè meglio.
Eric O Lebigot,

6

Nel caso in cui tu abbia più chiavi minime e desideri mantenerlo semplice

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']

4

Se non sei sicuro di non avere più valori minimi, suggerirei:

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

3

Modifica: questa è una risposta alla domanda originale dell'OP sulla chiave minima, non sulla risposta minima.


Puoi ottenere i tasti del dict usando la keysfunzione e hai ragione su come usare minper trovare il minimo di quell'elenco.


Non merita davvero un voto negativo, poiché la domanda originale del poster non era chiara come avrebbe potuto essere.
GreenMatt,

@ Space_C0wb0y: forse puoi essere così gentile da notare che l'OP ha modificato la sua domanda per significare qualcosa di diverso, dopo che ho risposto
Eli Bendersky,

3

Un altro approccio per affrontare il problema di più chiavi con lo stesso valore minimo:

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

2

Usa mincon un iteratore (per python 3 usa itemsinvece di iteritems); invece di lambda usa l' itemgetteroperatore from, che è più veloce di lambda.

from operator import itemgetter
min_key, _ = min(d.iteritems(), key=itemgetter(1))


1

Ho confrontato le seguenti tre opzioni:

    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 )

Uscita campione:

#option 1
236230
0:00:14.136808

#option 2
236230
0:00:00.458026

#option 3
236230
0:00:00.824048

0

per creare una classe ordinabile devi sovrascrivere 6 funzioni speciali, in modo che venga chiamato dalla funzione min ()

questi metodi sono __lt__ , __le__, __gt__, __ge__, __eq__ , __ne__in ordine minore, minore o uguale, maggiore di, maggiore o uguale, uguale, non uguale. ad esempio è necessario implementare __lt__come segue:

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

quindi è possibile utilizzare la funzione min come segue:

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

questo ha funzionato per me.


0
min(zip(d.values(), d.keys()))[1]

Utilizzare la funzione zip per creare un iteratore di tuple contenente valori e chiavi. Quindi avvolgilo con una funzione min che richiede il minimo in base al primo tasto. Ciò restituisce una tupla contenente una coppia (valore, chiave). L'indice di [1] viene utilizzato per ottenere la chiave corrispondente


2
Mentre questo codice può rispondere alla domanda, fornendo un contesto aggiuntivo riguardo al perché e / o al modo in cui questo codice risponde alla domanda migliora il suo valore a lungo termine.
β.εηοιτ.βε

@ β.εηοιτ.βε che meglio?
Raj

-1
# python 
d={320:1, 321:0, 322:3}
reduce(lambda x,y: x if d[x]<=d[y] else y, d.iterkeys())
  321

6
1) La riduzione è generalmente più lenta degli itertools. 2) La maggior parte delle implementazioni di ridurre può essere fatta più semplice con qualsiasi o tutti. 3) Sono un portavoce gigante per GvR. 4) Il modulo operatore rende superflue le lambda più semplici e comunque le lambda complesse dovrebbero essere definite come funzioni reali. Forse ho solo paura della programmazione funzionale. ;)
MikeD,

@miked: dimmi di più. cos'è gvr e qual è il modulo operatore? potresti pubblicare link? potrei conoscere altri, ma sono ancora solo un intermedio in Python. disposti a imparare! :-)
eruciforme il

GvR è Guido van Rossum, il benevolo dittatore di Python per la vita. Ecco un suo post di cinque anni che spiega perché i lisp-isms (mappa, filtro, riduzione, lambda) non hanno molto spazio in Python per il futuro, e quei motivi sono ancora veri oggi. Il modulo operatore ha sostituzioni per l' estrazione di membri : "lambda x: x [1]" rispetto a "itemgetter (1)" è un carattere più lungo e probabilmente impiega più tempo a comprenderlo. Sono fuori dallo spazio, ma fai domande!
MikeD,

@miked: vuoi primo morso alla mela? stackoverflow.com/questions/3292481/…
eruciform

Non è davvero necessario reimplementare qualcosa di incorporato in ( min()).
Eric O Lebigot,

-8

E 'questo quello che stai cercando?

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

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

Stampe 'quattordici'


8
-1: non è la domanda posta. Stai restituendo il valore con la chiave minima, OP vuole la chiave con il valore minimo
Brian S
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.