web-dev-qa-db-fra.com

Comment filtrer les clés de dictionnaire en fonction de ses valeurs correspondantes

J'ai:

dictionary = {"foo":12, "bar":2, "jim":4, "bob": 17}

Je veux parcourir ce dictionnaire, mais les valeurs au lieu des clés, afin que je puisse utiliser les valeurs dans une autre fonction.

Par exemple, je veux tester quelles valeurs de dictionnaire sont supérieures à 6, puis enregistrez leurs clés dans une liste. Mon code ressemble à ceci:

list = []
for c in dictionary:
    if c > 6:
        list.append(dictionary[c])
print list

et ensuite, dans un monde parfait, list comporterait toutes les clés dont la valeur est supérieure à 6. Cependant, ma boucle for ne fait que parcourir les clés; Je voudrais changer cela pour les valeurs!

Toute aide est grandement appréciée. Je vous remercie

58
Hoops
>>> d = {"foo": 12, "bar": 2, "jim": 4, "bob": 17}
>>> [k for k, v in d.items() if v > 6] # Use d.iteritems() on python 2.x
['bob', 'foo']

Je voudrais simplement mettre à jour cette réponse pour présenter également la solution de @glarrain que je me trouve avoir tendance à utiliser de nos jours.

[k for k in d if d[k] > 6]

Ceci est totalement compatible et ne nécessite pas une modification déroutante de .iteritems (.iteritems Évite de sauvegarder une liste en mémoire le Python 2 qui est corrigé dans = Python 3) à .items.

@ Prof.Falken a mentionné une solution à ce problème

from six import iteritems

qui résout efficacement les problèmes de compatibilité croisée MAIS nécessite le téléchargement du paquet six

Cependant, je ne suis pas tout à fait d’accord avec @glarrain pour dire que cette solution est plus lisible, qu’elle peut faire l’objet d’un débat et peut-être simplement une préférence personnelle même si Python n’est censé avoir qu’une seule façon de le faire. À mon avis, cela dépend de la situation (par exemple, vous pouvez avoir un nom de dictionnaire long que vous ne voulez pas taper deux fois ou vous voulez donner aux valeurs un nom plus lisible ou une autre raison).

Quelques timings intéressants:

Dans Python 2, la deuxième solution est plus rapide, dans Python 3, ils sont presque exactement égaux en vitesse brute.


$ python -m timeit -s 'd = {"foo": 12, "bar": 2, "jim": 4, "bob": 17};' '[k for k, v in d.items() if v > 6]'
1000000 loops, best of 3: 0.772 usec per loop
$ python -m timeit -s 'd = {"foo": 12, "bar": 2, "jim": 4, "bob": 17};' '[k for k, v in d.iteritems() if v > 6]'
1000000 loops, best of 3: 0.508 usec per loop
$ python -m timeit -s 'd = {"foo": 12, "bar": 2, "jim": 4, "bob": 17};' '[k for k in d if d[k] > 6]'
1000000 loops, best of 3: 0.45 usec per loop

$ python3 -m timeit -s 'd = {"foo": 12, "bar": 2, "jim": 4, "bob": 17};' '[k for k, v in d.items() if v > 6]'
1000000 loops, best of 3: 1.02 usec per loop
$ python3 -m timeit -s 'd = {"foo": 12, "bar": 2, "jim": 4, "bob": 17};' '[k for k in d if d[k] > 6]'
1000000 loops, best of 3: 1.02 usec per loop

Cependant, ce ne sont que des tests pour de petits dictionnaires, dans énorme je suis à peu près sûr que ne pas avoir de clé de recherche dans le dictionnaire (d[k]) Rendrait .items Beaucoup plus rapide. Et cela semble être le cas

$ python -m timeit -s 'd = {i: i for i in range(-10000000, 10000000)};' -n 1 '[k for k in d if d[k] > 6]'
1 loops, best of 3: 1.75 sec per loop
$ python -m timeit -s 'd = {i: i for i in range(-10000000, 10000000)};' -n 1 '[k for k, v in d.iteritems() if v > 6]'
1 loops, best of 3: 1.71 sec per loop
$ python3 -m timeit -s 'd = {i: i for i in range(-10000000, 10000000)};' -n 1 '[k for k in d if d[k] > 6]'
1 loops, best of 3: 3.08 sec per loop
$ python3 -m timeit -s 'd = {i: i for i in range(-10000000, 10000000)};' -n 1 '[k for k, v in d.items() if v > 6]'
1 loops, best of 3: 2.47 sec per loop
82
jamylak

Pour obtenir uniquement les valeurs, utilisez dictionary.values()

Pour obtenir des paires clé-valeur, utilisez dictionary.items()

36
Sionide21

Utilisez items ou iteritems dans le dictionnaire. Quelque chose comme:

list = []
for k, v in dictionary.iteritems():
  if v > 6:
    list.append(k)
print list
10
Vikas

Je pense que la meilleure façon de faire cela (en considérant la migration vers Python 3) est

>>> mydict = {'foo': 12, 'bar': 2, 'jim': 4, 'bob': 17}
>>> [k for k in mydict if mydict[k] > 6]
['bob', 'foo']

Le critère de "meilleur" est la lisibilité.

(Avertissement: ma réponse est basée sur la réponse d'Alex Martelli à une autre question https://stackoverflow.com/a/3744713/55641 et @ jamylak à cette question)

4
glarrain

Que dis-tu de ça:

dictionary = {"foo":12, "bar":2, "jim":4, "bob": 17}
for val in dictionary.values():
    # do something
4

Cela dépend si vous souhaitez modifier le dictionnaire (ajouter ou supprimer des éléments) ou non. Sinon, vous pouvez essayer:

for value in dictionary.itervalues():  #this returns a generator
     print "do something with the value"

Alternativement, si vous modifiez le dictionnaire, vous devriez parcourir une copie des valeurs:

for value in dictionary.values():  #this returns a list of values
     print "do something with the value"

Si vous souhaitez utiliser à la fois les clés et les valeurs, vous pouvez effectuer des itérations sur des paires à l'aide de dictionary.iteritems() ou dictionary.items()

2
uhz