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.

tjvr
fuente
¿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!

Alex Martelli
fuente
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.

Mark Rushakoff
fuente
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))
jpp
fuente
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
11

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

abyx
fuente
6
>>> d = {320:1, 321:0, 322:3}
>>> min(d, key=lambda k: d[k]) 
321
revs Daniel Stutzbach
fuente
@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']
netskink
fuente
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
"""
Tony Veijalainen
fuente
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.

Eli Bendersky
fuente
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]
PaulMcG
fuente
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))
Antti Haapala
fuente
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
fuente
¿Alguna idea de cómo calcular el valor más pequeño ARRIBA de cero?
Capitán Anónimo
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
svinec
fuente
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í.

Muhammad Korra
fuente
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

revs rajn
fuente
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
eruciforme
fuente
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'

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