python - Obtener clave por valor en el diccionario



15 Answers

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 información sobre las keys() y .values() en Python 3: Python: ¿la forma más sencilla de obtener una lista de valores de dict?

python dictionary

Hice una función que buscará las edades en un Dictionary y mostrará el nombre correspondiente:

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é cómo comparar y encontrar la edad, simplemente no sé cómo mostrar el nombre de la persona. Además, estoy recibiendo un KeyError debido a la línea 5. Sé que no es correcto, pero no puedo averiguar cómo hacer que busque hacia atrás.




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 ejecuté (en un MacBook Pro 2012)

>>> def method1(list,search_age):
...     for name,age in list.iteritems():
...             if age == search_age:
...                     return name
... 
>>> def method2(list,search_age):
...     return [name for name,age in list.iteritems() if age == search_age]
... 
>>> def method3(list,search_age):
...     return list.keys()[list.values().index(search_age)]

Los resultados de profile.run() en cada método 100000 veces:

Método 1:

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

Método 2:

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

Método 3:

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

Así que esto muestra que para un pequeño dict, el método 1 es el más rápido. Esto es más probable porque devuelve la primera coincidencia, a diferencia de todas las coincidencias como el método 2 (vea 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 ejecutado 10000 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

Así que aquí, el método 3 es mucho más rápido. Solo muestra el tamaño de tu dictado que afectará al método que elijas.

Notas: El método 2 devuelve una lista de todos los nombres, mientras que los métodos 1 y 3 solo devuelven la primera coincidencia. No he considerado el uso de la memoria. No estoy seguro de si el método 3 crea 2 listas adicionales (claves () y valores ()) y las almacena en la memoria.




a = {'a':1,'b':2,'c':3}
{v:k for k, v in a.items()}[1]

o mejor

{k:v for k, v in a.items() if v == 1}



Aquí está mi opinión sobre este problema. :) Acabo de empezar a aprender Python, así que llamo a esto:

Solución "El Comprensible para principiantes".

#Code without comments.

list1 = {'george':16,'amber':19, 'Garry':19}
search_age = raw_input("Provide age: ")
print
search_age = int(search_age)

listByAge = {}

for name, age in list1.items():
    if age == search_age:
        age = str(age)
        results = name + " " +age
        print results

        age2 = int(age)
        listByAge[name] = listByAge.get(name,0)+age2

print
print listByAge

.

#Code with comments.
#I've added another name with the same age to the list.
list1 = {'george':16,'amber':19, 'Garry':19}
#Original code.
search_age = raw_input("Provide age: ")
print
#Because raw_input gives a string, we need to convert it to int,
#so we can search the dictionary list with it.
search_age = int(search_age)

#Here we define another empty dictionary, to store the results in a more 
#permanent way.
listByAge = {}

#We use double variable iteration, so we get both the name and age 
#on each run of the loop.
for name, age in list1.items():
    #Here we check if the User Defined age = the age parameter 
    #for this run of the loop.
    if age == search_age:
        #Here we convert Age back to string, because we will concatenate it 
        #with the person's name. 
        age = str(age)
        #Here we concatenate.
        results = name + " " +age
        #If you want just the names and ages displayed you can delete
        #the code after "print results". If you want them stored, don't...
        print results

        #Here we create a second variable that uses the value of
        #the age for the current person in the list.
        #For example if "Anna" is "10", age2 = 10,
        #integer value which we can use in addition.
        age2 = int(age)
        #Here we use the method that checks or creates values in dictionaries.
        #We create a new entry for each name that matches the User Defined Age
        #with default value of 0, and then we add the value from age2.
        listByAge[name] = listByAge.get(name,0)+age2

#Here we print the new dictionary with the users with User Defined Age.
print
print listByAge

.

#Results
Running: *\test.py (Thu Jun 06 05:10:02 2013)

Provide age: 19

amber 19
Garry 19

{'amber': 19, 'Garry': 19}

Execution Successful!



Si desea buscar la clave por el valor, puede usar una comprensión del diccionario para crear un diccionario de búsqueda y luego usarla para encontrar la clave a partir del valor.

lookup = {value: key for key, value in self.data}
lookup[value]



Aquí, recover_key toma el diccionario y el valor para encontrar en el diccionario. Luego hacemos un bucle sobre las claves en el diccionario y hacemos una comparación con la de valor y devolvemos esa clave en particular.

def recover_key(dicty,value):
    for a_key in dicty.keys():
        if (dicty[a_key] == value):
            return a_key



se responde, pero se puede hacer con un elegante uso de 'map / reduce', por ejemplo:

def find_key(value, dictionary):
    return reduce(lambda x, y: x if x is not None else y,
                  map(lambda x: x[0] if x[1] == value else None, 
                      dictionary.iteritems()))



get_key = lambda v, d: next(k for k in d if d[k] is v)



Aquí está mi opinión sobre ello. Esto es bueno para mostrar múltiples resultados en caso de que necesite uno. Así que agregué la lista también

myList = {'george':16,'amber':19, 'rachel':19, 
           'david':15 }                         #Setting the dictionary
result=[]                                       #Making ready of the result list
search_age = int(input('Enter age '))

for keywords in myList.keys():
    if myList[keywords] ==search_age:
    result.append(keywords)                    #This part, we are making list of results

for res in result:                             #We are now printing the results
    print(res)

Y eso es...




Sé que esto es antiguo, pero podría encontrar fácilmente a todas las personas en la lista con su edad de búsqueda usando la comprensión de lista.

ages = {'george':16,'amber':19}
search = 16
print([name for (name, age) in ages.items() if age == search])



Encontré esta answer muy efectiva pero aún así no es muy fácil de leer para mí.

Para que quede más claro, puede invertir la clave y el valor de un diccionario. Esto es hacer que los valores de las claves y las claves de los valores, como se ve here .

mydict = {'george':16,'amber':19}
res = dict((v,k) for k,v in mydict.iteritems())
print(res[16]) # Prints george

o

mydict = {'george':16,'amber':19}
dict((v,k) for k,v in mydict.iteritems())[16]

que es esencialmente lo mismo que esta otra answer .




A veces puede ser necesario int ():

titleDic = {'Фильмы':1, 'Музыка':2}

def categoryTitleForNumber(self, num):
    search_title = ''
    for title, titleNum in self.titleDic.items():
        if int(titleNum) == int(num):
            search_title = title
    return search_title



Ya se ha respondido, pero como varias personas mencionaron revertir el diccionario, esta es la forma en que lo hace en una línea (asumiendo el mapeo 1: 1) y algunos datos de perf:

python 2.6:

reversedict = dict([(value, key) for key, value in mydict.iteritems()])

2.7+:

reversedict = {value:key for key, value in mydict.iteritems()}

Si piensa que no es 1: 1, aún puede crear un mapeo inverso razonable con un par de líneas:

reversedict = defaultdict(list)
[reversedict[value].append(key) for key, value in mydict.iteritems()]

qué tan lento es esto: más lento que una búsqueda simple, pero no tan lento como podría pensar - en un diccionario de entrada 'directo' 100000, una búsqueda 'rápida' (es decir, buscar un valor que debería estar al principio de las teclas) fue aproximadamente 10 veces más rápido que revertir todo el diccionario, y una búsqueda 'lenta' (hacia el final) aproximadamente 4-5 veces más rápido. Así que después de un máximo de 10 búsquedas, se paga por sí mismo.

la segunda versión (con listas por elemento) toma aproximadamente 2.5x mientras la versión simple.

largedict = dict((x,x) for x in range(100000))

# Should be slow, has to search 90000 entries before it finds it
In [26]: %timeit largedict.keys()[largedict.values().index(90000)]
100 loops, best of 3: 4.81 ms per loop

# Should be fast, has to only search 9 entries to find it. 
In [27]: %timeit largedict.keys()[largedict.values().index(9)]
100 loops, best of 3: 2.94 ms per loop

# How about using iterkeys() instead of keys()?
# These are faster, because you don't have to create the entire keys array.
# You DO have to create the entire values array - more on that later.

In [31]: %timeit islice(largedict.iterkeys(), largedict.values().index(90000))
100 loops, best of 3: 3.38 ms per loop

In [32]: %timeit islice(largedict.iterkeys(), largedict.values().index(9))
1000 loops, best of 3: 1.48 ms per loop

In [24]: %timeit reversedict = dict([(value, key) for key, value in largedict.iteritems()])
10 loops, best of 3: 22.9 ms per loop

In [23]: %%timeit
....: reversedict = defaultdict(list)
....: [reversedict[value].append(key) for key, value in largedict.iteritems()]
....:
10 loops, best of 3: 53.6 ms per loop

También tuvo algunos resultados interesantes con ifilter. Teóricamente, ifilter debería ser más rápido, ya que podemos usar itervalues ​​() y posiblemente no tener que crear / ir a través de toda la lista de valores. En la práctica, los resultados fueron ... impares ...

In [72]: %%timeit
....: myf = ifilter(lambda x: x[1] == 90000, largedict.iteritems())
....: myf.next()[0]
....:
100 loops, best of 3: 15.1 ms per loop

In [73]: %%timeit
....: myf = ifilter(lambda x: x[1] == 9, largedict.iteritems())
....: myf.next()[0]
....:
100000 loops, best of 3: 2.36 us per loop

Por lo tanto, para las compensaciones pequeñas, fue mucho más rápido que cualquier versión anterior (2.36 * u * S versus un mínimo de 1.48 * m * S para casos anteriores). Sin embargo, para grandes compensaciones cerca del final de la lista, fue dramáticamente más lento (15.1ms vs. el mismo 1.48mS). Los pequeños ahorros en el extremo inferior no valen el costo en el extremo superior, imho.




Así es como accedes al diccionario para hacer lo que quieres:

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

por supuesto, sus nombres son tan desiguales que parece que imprimiría una edad, pero SÍ imprime el nombre. Ya que está accediendo por nombre, se vuelve más comprensible si escribe:

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

Mejor todavía:

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



Aquí hay una solución que funciona tanto en Python 2 como en Python 3:

dict((v, k) for k, v in list.items())[search_age]

La parte hasta que [search_age] construye el diccionario inverso (donde los valores son claves y viceversa). Podría crear un método auxiliar que almacenará en caché este diccionario invertido de la siguiente manera:

def find_name(age, _rev_lookup=dict((v, k) for k, v in ages_by_name.items())):
    return _rev_lookup[age]

o incluso más generalmente una fábrica que crearía un método de búsqueda de nombre por edad para una o más de sus listas

def create_name_finder(ages_by_name):
    names_by_age = dict((v, k) for k, v in ages_by_name.items())
    def find_name(age):
      return names_by_age[age]

para que pudieras hacer:

find_teen_by_age = create_name_finder({'george':16,'amber':19})
...
find_teen_by_age(search_age)

Tenga en cuenta que he cambiado el nombre de la list a ages_by_name ya que el primero es un tipo predefinido.






Related