Obtener clave por valor en el diccionario

Resuelto user998316 asked hace 12 años • 43 respuestas

Hice una función que buscará edades en a Dictionaryy mostrará el nombre coincidente:

dictionary = {'george' : 16, 'amber' : 19}
search_age = raw_input("Provide age")
for age in dictionary.values():
    if age == search_age:
        name = dictionary[age]
        print name

Sé comparar y encontrar la edad, pero no sé cómo mostrar el nombre de la persona. Además, recibo un error KeyErrordebido a la línea 5. Sé que no es correcto, pero no sé cómo hacer que busque hacia atrás.

user998316 avatar Nov 06 '11 04:11 user998316
Aceptado
mydict = {'george': 16, 'amber': 19}
print mydict.keys()[mydict.values().index(16)]  # Prints george

O en Python 3.x:

mydict = {'george': 16, 'amber': 19}
print(list(mydict.keys())[list(mydict.values()).index(16)])  # Prints george

Básicamente, separa los valores del diccionario en una lista, encuentra la posición del valor que tiene y obtiene la clave en esa posición.

Más sobre keys()y .values()en Python 3: ¿Cómo puedo obtener una lista de valores de dict?

Stênio Elson avatar Oct 31 '2012 00:10 Stênio Elson

No hay ninguno. dictno está diseñado para usarse de esta manera.

dictionary = {'george': 16, 'amber': 19}
search_age = input("Provide age")
for name, age in dictionary.items():  # for name, age in dictionary.iteritems():  (for Python 2.x)
    if age == search_age:
        print(name)
Cat Plus Plus avatar Nov 05 '2011 21:11 Cat Plus Plus

Si quieres tanto el nombre como la edad, deberías usar .items()la que te proporciona las tuplas clave (key, value):

for name, age in mydict.items():
    if age == search_age:
        print name

Puede descomprimir la tupla en dos variables separadas directamente en el forbucle y luego hacer coincidir la edad.

También deberías considerar invertir el diccionario si generalmente vas a buscar por edad y no hay dos personas que tengan la misma edad:

{16: 'george', 19: 'amber'}

para que puedas buscar el nombre de una edad con solo hacer

mydict[search_age]

Lo he estado llamando mydicten lugar de listporque listes el nombre de un tipo integrado y no deberías usar ese nombre para nada más.

Incluso puedes obtener una lista de todas las personas con una edad determinada en una línea:

[name for name, age in mydict.items() if age == search_age]

o si hay una sola persona con cada edad:

next((name for name, age in mydict.items() if age == search_age), None)

que solo te dará Nonesi no hay nadie con esa edad.

Finalmente, si dictes largo y estás en Python 2, deberías considerar usarlo .iteritems()en lugar de .items()como lo hizo Cat Plus Plus en su respuesta, ya que no es necesario hacer una copia de la lista.

agf avatar Nov 05 '2011 21:11 agf

Pensé que sería interesante señalar qué métodos son los más rápidos y en qué escenario:

Aquí hay algunas pruebas que realicé (en una MacBook Pro 2012)

def method1(dict, search_age):
    for name, age in dict.iteritems():
        if age == search_age:
            return name

def method2(dict, search_age):
    return [name for name,age in dict.iteritems() if age == search_age]

def method3(dict, search_age):
    return dict.keys()[dict.values().index(search_age)]

Resultados de profile.run()cada método 100.000 veces:

Método 1:

>>> profile.run("for i in range(0,100000): method1(dict, 16)")
     200004 function calls in 1.173 seconds

Método 2:

>>> profile.run("for i in range(0,100000): method2(dict, 16)")
     200004 function calls in 1.222 seconds

Método 3:

>>> profile.run("for i in range(0,100000): method3(dict, 16)")
     400004 function calls in 2.125 seconds

Esto muestra que para un dictado pequeño, el método 1 es el más rápido. Lo más probable es que esto se deba a que devuelve la primera coincidencia, a diferencia de todas las coincidencias como en el método 2 (consulte la nota a continuación).


Curiosamente, al realizar las mismas pruebas en un dict que tengo con 2700 entradas, obtengo resultados bastante diferentes (esta vez lo ejecuto 10,000 veces):

Método 1:

>>> profile.run("for i in range(0,10000): method1(UIC_CRS,'7088380')")
     20004 function calls in 2.928 seconds

Método 2:

>>> profile.run("for i in range(0,10000): method2(UIC_CRS,'7088380')")
     20004 function calls in 3.872 seconds

Método 3:

>>> profile.run("for i in range(0,10000): method3(UIC_CRS,'7088380')")
     40004 function calls in 1.176 seconds

Entonces aquí, el método 3 es mucho más rápido. Solo sirve para mostrar que el tamaño de su dictado afectará el método que elija.

Notas:

  • El método 2 devuelve una lista de todos los nombres, mientras que los métodos 1 y 3 devuelven sólo la primera coincidencia.
  • No he considerado el uso de memoria. No estoy seguro de si el método 3 crea 2 listas adicionales ( keys()y values()) y las almacena en la memoria.
Patrick avatar Jan 31 '2013 11:01 Patrick