web-dev-qa-db-fra.com

Obtenir clé par valeur dans le dictionnaire

J'ai créé une fonction qui va chercher des âges dans une Dictionary et montrer le nom correspondant:

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

Je sais comment comparer et trouver l'âge, mais je ne sais pas comment montrer le nom de la personne. De plus, je reçois un KeyError à cause de la ligne 5. Je sais que ce n'est pas correct, mais je ne vois pas comment faire en sorte que la recherche soit inversée.

449
user998316

Il n'y en a pas. dict n'est pas destiné à être utilisé de cette façon.

for name, age in dictionary.items():    # for name, age in dictionary.iteritems():  (for Python 2.x)
    if age == search_age:
        print(name)
403
Cat Plus Plus
mydict = {'george':16,'amber':19}
print mydict.keys()[mydict.values().index(16)] # Prints george

Ou en Python 3.x:

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

Fondamentalement, il sépare les valeurs du dictionnaire dans une liste, trouve la position de la valeur que vous avez et obtient la clé à cette position.

En savoir plus sur keys() et .values() dans Python 3: Python: le moyen le plus simple d’obtenir une liste de valeurs à partir de dict?

450
Stênio Elson

Si vous voulez à la fois le nom et l'âge, vous devriez utiliser .items() qui vous donne la clé (key, value) tuples:

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

Vous pouvez décompresser le tuple en deux variables distinctes directement dans la boucle for, puis faire correspondre l'âge.

Vous devriez également envisager d'inverser le dictionnaire si vous allez généralement chercher par âge et qu'il n'y a pas deux personnes du même âge:

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

afin que vous puissiez rechercher le nom d'un âge en faisant simplement

mydict[search_age]

Je l'ai appelé mydict au lieu de list car list est le nom d'un type intégré, et vous ne devez utiliser ce nom pour rien d'autre.

Vous pouvez même obtenir une liste de toutes les personnes d'un même âge en une seule ligne:

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

ou s'il n'y a qu'une personne par âge:

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

ce qui vous donnera simplement None s'il n'y a personne avec cet âge.

Enfin, si la variable dict est longue et que vous utilisez Python 2, vous devriez envisager d’utiliser .iteritems() au lieu de .items() comme l’a fait Cat Plus Plus dans sa réponse, car il n’est pas nécessaire de copier cette liste.

202
agf

J'ai pensé qu'il serait intéressant d'indiquer quelles méthodes sont les plus rapides et dans quel scénario:

Voici quelques tests que j'ai effectués (sur 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)]

Résultats de profile.run() sur chaque méthode 100 000 fois:

Méthode 1:

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

Méthode 2:

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

Méthode 3:

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

Cela montre donc que pour un petit dict, la méthode 1 est la plus rapide. Ceci est probablement dû au fait qu'il renvoie la première correspondance, par opposition à toutes les correspondances telles que la méthode 2 (voir la remarque ci-dessous).


Fait intéressant, en effectuant les mêmes tests sur un dict que j'ai avec 2700 entrées, j'obtiens des résultats assez différents (cette fois-ci exécutés 10000 fois):

Méthode 1:

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

Méthode 2:

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

Méthode 3:

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

Donc ici, la méthode 3 est beaucoup plus rapide. Va juste pour montrer que la taille de votre dict affectera quelle méthode vous choisissez.

Remarques: La méthode 2 renvoie une liste de tous noms, alors que les méthodes 1 et 3 ne renvoient que la première correspondance . Je n'ai pas envisagé l'utilisation de la mémoire. Je ne suis pas sûr que la méthode 3 crée 2 listes supplémentaires (keys () et values ​​()) et les stocke en mémoire.

58
Patrick

version à une ligne: (i est un vieux dictionnaire, p est un dictionnaire inversé)

explication: i.keys () et i.values ​​() renvoient deux listes contenant les clés et les valeurs du dictionnaire. La fonction Zip a la capacité de relier des listes pour produire un dictionnaire.

avertissement: cela ne fonctionnerait que si les valeurs sont hashable et uniques.

p = dict(Zip(i.values(),i.keys()))
38
fanny
a = {'a':1,'b':2,'c':3}
{v:k for k, v in a.items()}[1]

ou mieux

{k:v for k, v in a.items() if v == 1}
22
Jelen
lKey = [key for key, value in lDictionary.iteritems() if value == lValue][0]
19
faham

Vous pouvez obtenir la clé en utilisant les méthodes dict.keys() , dict.values() et list.index() , voir les exemples de code ci-dessous:

names_dict = {'george':16,'amber':19}
search_age = int(raw_input("Provide age"))
key = names_dict.keys()[names_dict.values().index(search_age)]
9
Andriy Ivaneyko

Voici mon point de vue sur ce problème. :) Je viens de commencer à apprendre Python, alors j'appelle ça:

"La solution compréhensible pour les débutants".

#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!
9
Deithrian

Si vous souhaitez rechercher la clé par valeur, vous pouvez utiliser un dictionnaire de compréhension pour créer un dictionnaire de recherche, puis l'utiliser pour rechercher la clé à partir de la valeur.

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

J'ai trouvé ceci réponse très efficace mais toujours pas très facile à lire pour moi.

Pour que ce soit plus clair, vous pouvez inverser la clé et la valeur d’un dictionnaire. Il s'agit de rendre les valeurs clés et les valeurs clés, comme vu ici .

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

ou

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

qui est essentiellement le même que cet autre répondre .

6
Rafael Valero

Essayez ce one-liner pour inverser un dictionnaire:

reversed_dictionary = dict(map(reversed, dictionary.items()))
6
johnaphun

Ici, recover_key prend le dictionnaire et la valeur à trouver dans le dictionnaire. Nous parcourons ensuite les clés dans le dictionnaire et faisons une comparaison avec celle de valeur et retournons cette clé particulière.

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

Pensez à utiliser des pandas. Comme indiqué dans "Python pour l'analyse des données" de William McKinney

Une autre façon de penser à une série est comme une longueur fixe, ordonnée dict, car il s'agit d'une correspondance entre les valeurs d'index et les valeurs de données. Ça peut être utilisé dans de nombreux contextes où vous pourriez utiliser un dict.

import pandas as pd
list = {'george':16,'amber':19}
lookup_list = pd.Series(list)

Pour interroger votre série, procédez comme suit:

lookup_list[lookup_list.values == 19]

Quels rendements:

Out[1]: 
amber    19
dtype: int64

Si vous voulez faire autre chose avec la sortie, transformer le Réponse en une liste peut être utile:

answer = lookup_list[lookup_list.values == 19].index
answer = pd.Index.tolist(answer)
6
Axel
get_key = lambda v, d: next(k for k in d if d[k] is v)
4
Brett
for name in mydict.keys():
    if mydict[name] == search_age:
        print name 
        #or do something else with it. 
        #if in a function append to a temporary list, 
        #then after the loop return the list
4
patrick

vous y répondez, mais vous pouvez le faire avec une utilisation "carte/réduction" sophistiquée, par exemple:

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()))
4
formiaczek
def get_Value(dic,value):
    for name in dic:
        if dic[name] == value:
            del dic[name]
            return name
4
Raj Damani

J'espère que cela pourrait aider ...

for key in list:
   if list[key] == search_value:
       return key
3
Nat

Il n'y a pas de moyen facile de trouver une clé dans une liste en "recherchant" la valeur. Toutefois, si vous connaissez la valeur, en effectuant une itération à travers les clés, vous pouvez rechercher des valeurs dans le dictionnaire par élément. Si D [élément] où D est un objet du dictionnaire, est égal à la clé que vous essayez de rechercher, vous pouvez exécuter du code.

D = {'ALi': 20, 'Marina': 12, 'George':16}
age = int(input('enter age:\t'))  
for element in D.keys():
    if D[element] == age:
        print(element)
3
Ethan

Je sais que c'est vieux, mais vous pouvez facilement trouver toutes les personnes dans la liste avec votre âge de recherche en utilisant la compréhension par liste.

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

voici mon point de vue sur elle. C'est bien pour afficher plusieurs résultats au cas où vous en auriez besoin. Alors j'ai ajouté la liste aussi 

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)

Et c'est tout... 

3
user3649211

Vous devez utiliser un dictionnaire et inverser ce dictionnaire. Cela signifie que vous avez besoin d'une autre structure de données. Si vous êtes dans python 3, utilisez le module enum, mais si vous utilisez python 2.7, utilisez enum34 qui est de nouveau porté pour python 2.

Exemple:

from enum import Enum

class Color(Enum): 
    red = 1 
    green = 2 
    blue = 3

>>> print(Color.red) 
Color.red

>>> print(repr(Color.red)) 
<color.red: 1=""> 

>>> type(Color.red) 
<enum 'color'=""> 
>>> isinstance(Color.green, Color) 
True 

>>> member = Color.red 
>>> member.name 
'red' 
>>> member.value 
1 
2
Hamid FzM

Parfois, int () peut être nécessaire:

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

Cat Plus Plus a mentionné que ce n'est pas la façon dont un dictionnaire est destiné à être utilisé. Voici pourquoi:

La définition d'un dictionnaire est analogue à celle d'une cartographie en mathématiques. Dans ce cas, un dict est un mappage de K (l'ensemble de clés) sur V (les valeurs) - mais pas l'inverse. Si vous déréférencez un dict, vous vous attendez à obtenir exactement une valeur renvoyée. Cependant, il est parfaitement légal que différentes clés se mappent sur la même valeur, par exemple:

d = { k1 : v1, k2 : v2, k3 : v1}

Lorsque vous recherchez une clé par sa valeur correspondante, vous inversez le dictionnaire. Mais une cartographie n'est pas forcément inversible! Dans cet exemple, demander la clé correspondant à v1 pourrait donner k1 ou k3. Devez-vous retourner les deux? Juste le premier trouvé? C'est pourquoi indexof () n'est pas défini pour les dictionnaires.

Si vous connaissez vos données, vous pouvez le faire. Mais une API ne peut pas supposer qu'un dictionnaire arbitraire est inversible, d’où l’absence d’une telle opération.

2
Dan Ahlquist
dictionary = {'george' : 16, 'amber' : 19}
search_age = raw_input("Provide age")
key = [filter( lambda x: dictionary[x] == k  , dictionary ),[None]][0] 
# key = None from [None] which is a safeguard for not found.

Pour plusieurs occurrences, utilisez:

keys = [filter( lambda x: dictionary[x] == k  , dictionary )]
1
Cesar

Voici comment vous accédez au dictionnaire pour faire ce que vous voulez:

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

bien sûr, vos noms sont si décalés qu'il semble que ce serait imprimer un âge, mais le nom est imprimé. Puisque vous accédez par nom, cela devient plus compréhensible si vous écrivez:

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

Mieux encore: 

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
1
Surest Texas
d= {'george':16,'amber':19}

dict((v,k) for k,v in d.items()).get(16)

La sortie est la suivante:

-> prints george
1
Jeroen

déjà été répondu, mais puisque plusieurs personnes ont mentionné l’inversion du dictionnaire, voici comment procéder en une seule ligne (en supposant un mappage 1: 1) et quelques données de performances:

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 vous pensez que ce n'est pas 1: 1, vous pouvez toujours créer une correspondance inverse raisonnable avec quelques lignes:

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

À quel point est-ce lent: plus lent qu'une simple recherche, mais pas aussi lent qu'on pourrait le penser - dans un dictionnaire 'simple' 100 000 entrées, une recherche 'rapide' (c'est-à-dire la recherche d'une valeur qui devrait être au début dans les clés) était environ 10 fois plus rapide que l’inversion du dictionnaire entier, et une recherche "lente" (vers la fin) environ 4 à 5 fois plus rapide. Donc, après environ 10 recherches au maximum, tout est payé. 

la deuxième version (avec des listes par élément) prend environ 2,5 fois plus longtemps que la version 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

Aussi eu quelques résultats intéressants avec ifilter. Théoriquement, ifilter devrait être plus rapide, en ce sens que nous pouvons utiliser itervalues ​​() et éventuellement ne pas avoir à créer/parcourir toute la liste de valeurs. En pratique, les résultats ont été ... curieux ...

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

Ainsi, pour les petits décalages, il était considérablement plus rapide que toute version précédente (2,36 * u * S contre un minimum de 1,48 * m * S pour les cas précédents). Cependant, pour les grands décalages vers la fin de la liste, il était considérablement plus lent (15,1 ms contre le même 1,48 mS). Les petites économies au bas de gamme ne valent pas le coût au haut de gamme, à mon humble avis. 

1
Corley Brigman

Un moyen simple de faire cela pourrait être:

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

Cela retournera une liste des clés avec une valeur qui correspond à search_age. Vous pouvez également remplacer "list == search_age" par toute autre instruction de conditions, si nécessaire.

0
Meilin He

nous pouvons obtenir la Key de dict par:

def getKey(dict,value):
     return [key for key in dict.keys() if (dict[key] == value)]
0
Sakhri Houssem

J'ai essayé de lire autant de solutions que possible pour éviter de donner une réponse en double. Toutefois, si vous travaillez sur un dictionnaire dont les valeurs sont contenues dans des listes et si vous souhaitez obtenir des clés contenant un élément particulier, vous pouvez le faire:

d = {'Adams': [18, 29, 30],
     'Allen': [9, 27],
     'Anderson': [24, 26],
     'Bailey': [7, 30],
     'Baker': [31, 7, 10, 19],
     'Barnes': [22, 31, 10, 21],
     'Bell': [2, 24, 17, 26]}

Trouvons maintenant les noms qui ont 24 dans leurs valeurs.

for key in d.keys():    
    if 24 in d[key]:
        print(key)

Cela fonctionnerait aussi avec plusieurs valeurs. 

0
cyber-math

Juste ma réponse dans lambda et filter.

filter( lambda x, dictionary=dictionary, search_age=int(search_age): dictionary[x] == search_age  , dictionary )
0
Bishwas Mishra

Voici une solution qui fonctionne à la fois en Python 2 et en Python 3:

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

La partie jusqu'à [search_age] construit le dictionnaire inverse (où les valeurs sont des clés et inversement) . Vous pouvez créer une méthode d'assistance qui mettra en cache ce dictionnaire inversé comme suit:

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

ou même plus généralement une usine qui créerait une méthode de recherche par nom par âge pour une ou plusieurs de vos listes

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]

alors vous seriez capable de faire:

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

Notez que j'ai renommé list en ages_by_name car le premier est un type prédéfini.

0
eold