Obtener la clave correspondiente al valor mínimo dentro de un diccionario


305

Si tengo un diccionario de Python, ¿cómo obtengo la clave de la entrada que contiene el valor mínimo?

Estaba pensando en algo que ver con la min()función ...

Dada la entrada:

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

Volvería 321.


¿Error tipográfico en tu declaración? De lo contrario, ¿por qué 321? ¿No debería ser 320?
GreenMatt

3
@myself: Bien, ahora veo: lo que se desea es la clave de la entrada donde el valor de la entrada es el mínimo. Mejor redacción de la pregunta, por favor, ya que otros obviamente pensaron lo mismo que yo.
GreenMatt

2
Día de reconocimiento de la estructura de datos: si solo consulta (o elimina) el elemento mínimo, considere usar una cola o montón prioritario.
Coronel Panic

Respuestas:


597

Lo mejor: ¡ min(d, key=d.get)no hay razón para interponer una lambdacapa de indirección inútil o extraer elementos o claves!


55
@ KarelBílek significa que pasó como "d" una lista [11, 22, 33], por ejemplo , en lugar de un diccionario, por ejemplo {1: 11, 2:22, 3:33}. 'd.get' es válido para un diccionario, pero no para una lista.
ToolmakerSteve

99
¿Qué pasa si dos claves diferentes tienen el mismo valor? y ambos resultan ser el valor más pequeño? ¿Cómo puedes hacer que regrese ambos?
user3226932

55
¿Se puede usar esta técnica si los valores dict son listas, por ejemplo d={"a":[10, None], "b":[20, None]}, donde el mínimo se calcula a partir de d [clave] [0]?
TrakJohnson

44
¿Como funciona esto? Qué tipo de función min es esa, pensé que min () solo tomaba valores individuales o listas como argumentos. ¿Cómo se repite en todas las entradas del diccionario?
azureai

2
min()devolver el valor en el primer valor en ordenado. clave designar la forma de ordenar los valores. key=d.getsignifica que la lista se ordenará por valores del diccionario.
notilas 06/0618

45

Aquí hay una respuesta que realmente da la solución que solicitó el 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()Sin embargo, el uso será más eficiente para diccionarios más grandes.


3
En lugar de la lambda puedes usar operator.itemgetter(1).
Philipp

2
en cambio el uso lambda d.get
Texom512

Esto no devuelve la clave como se le pidió, sino el par (clave, valor).
Eric O Lebigot

14

Para varias claves que tienen el mismo valor más bajo, puede usar una lista de comprensión:

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 versión funcional equivalente:

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

1
Su respuesta es muy útil y otros probablemente estén de acuerdo: vea los múltiples comentarios para ese asunto en la respuesta aceptada. Sin embargo, necesitaba volver dos veces para encontrarlo: ¿consideraría proponer una edición a la respuesta aceptada? La tuya es en realidad complementaria.
jmon12


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

@SilentGhost, @ blob8108: ¡Oh! Copiar y pegar snafu. Corregido ahora.
Daniel Stutzbach

Buena solución, creo, pero la función anónima solo agrega una capa de indirección: key=d.getes mejor.
Eric O Lebigot

6

Para el caso en el que tiene varias claves mínimas y desea que sea 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']

4

Si no está seguro de que no tiene múltiples valores mínimos, sugeriría:

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

Editar: esta es una respuesta a la pregunta original del OP sobre la clave mínima, no la respuesta mínima.


Puede obtener las claves del dict usando la keysfunción, y tiene razón al usar minpara encontrar el mínimo de esa lista.


Realmente no merece un voto negativo, ya que la pregunta original del afiche no era tan clara como podría haber sido.
GreenMatt

@ Space_C0wb0y: tal vez puedas ser tan amable de notar que el OP editó su pregunta para que signifique algo diferente, después de que respondí
Eli Bendersky

3

Otro enfoque para abordar el problema de las claves múltiples con el mismo valor mínimo:

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

Usar mincon un iterador (para uso de Python 3 en itemslugar de iteritems); en lugar de lambda, use el itemgetteroperador from, que es más rápido que lambda.

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


1

Comparé cómo funcionan las siguientes tres opciones:

    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 )

Salida de muestra:

#option 1
236230
0:00:14.136808

#option 2
236230
0:00:00.458026

#option 3
236230
0:00:00.824048

0

Para crear una clase ordenable, debe anular 6 funciones especiales, para que la función min () la llame

estos métodos están __lt__ , __le__, __gt__, __ge__, __eq__ , __ne__en orden para que sean menores que, menores que o iguales, mayores que, mayores que o iguales, iguales, no iguales. por ejemplo, debe implementar __lt__lo siguiente:

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

entonces puede usar la función min de la siguiente manera:

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

Esto funcionó para mí.


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

Use la función zip para crear un iterador de tuplas que contengan valores y claves. Luego envuélvala con una función min que tome el mínimo basado en la primera tecla. Esto devuelve una tupla que contiene un par (valor, clave). El índice de [1] se usa para obtener la clave correspondiente


2
Si bien este código puede responder a la pregunta, proporcionar un contexto adicional con respecto a por qué y / o cómo este código responde a la pregunta mejora su valor a largo plazo.
β.εηοιτ.βε

@ β.εηοιτ.βε que mejor?
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

66
1) Reducir es generalmente más lento que las herramientas de iterto. 2) La mayoría de las implementaciones de reduce pueden hacerse más simples con cualquiera o con todas. 3) Soy un portavoz gigante para GvR. 4) El módulo del operador hace innecesarios los lambdas más simples, y los lambdas complejos deben definirse como funciones reales de todos modos. Tal vez solo tengo miedo de la programación funcional. ;)
MikeD

@miked: cuéntame más. ¿Qué es gvr y cuál es el módulo del operador? podrías publicar enlaces? Puedo conocer a otros, pero sigo siendo un intermediario en Python. ¡dispuesto a aprender! :-)
eruciforme

GvR es Guido van Rossum, el dictador benevolente de por vida de Python. Aquí hay una publicación de cinco años de él que explica por qué los lisp-isms (mapa, filtro, reducción, lambda) no tienen mucho lugar en Python en el futuro, y esas razones aún son ciertas hoy en día. El módulo del operador tiene reemplazos para extraer miembros : "lambda x: x [1]" en comparación con "itemgetter (1)" es un carácter más largo y posiblemente demore más en entenderse. Estoy sin espacio, ¡pero hago preguntas!
MikeD

@miked: ¿quieres el primer bocado de la manzana? stackoverflow.com/questions/3292481/…
eruciforme el

Realmente no hay necesidad de reimplementar algo integrado ( min()).
Eric O Lebigot

-8

¿Es esto lo que estás buscando?

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

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

Imprime 'catorce'


8
-1: no es lo que hizo la pregunta. Está devolviendo el valor con la clave mínima, OP quiere clave con el valor mínimo
Brian S
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.