Dictionnaire Python: obtenir la liste des valeurs pour la liste des clés

199

Existe-t-il un moyen intégré / rapide d'utiliser une liste de clés d'un dictionnaire pour obtenir une liste des éléments correspondants?

Par exemple j'ai:

>>> mydict = {'one': 1, 'two': 2, 'three': 3}
>>> mykeys = ['three', 'one']

Comment puis-je utiliser mykeyspour obtenir les valeurs correspondantes dans le dictionnaire sous forme de liste?

>>> mydict.WHAT_GOES_HERE(mykeys)
[3, 1]
FazJaxton
la source

Réponses:

217

Une compréhension de liste semble être un bon moyen de le faire:

>>> [mydict[x] for x in mykeys]
[3, 1]
FazJaxton
la source
1
S'il mydicts'agit d'un appel de fonction (qui renvoie un dict), cela appelle la fonction plusieurs fois, non?
endolith
1
@endolith Yes it will
Eric Romrell
111

Quelques autres moyens que list-comp:

  • Construisez la liste et lancez une exception si la clé est introuvable: map(mydict.__getitem__, mykeys)
  • Construisez la liste avec Nonesi la clé est introuvable:map(mydict.get, mykeys)

Alternativement, using operator.itemgetterpeut retourner un tuple:

from operator import itemgetter
myvalues = itemgetter(*mykeys)(mydict)
# use `list(...)` if list is required

Remarque : en Python3, maprenvoie un itérateur plutôt qu'une liste. Utilisez list(map(...))pour une liste.

Jon Clements
la source
60

Une petite comparaison de vitesse:

Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Dec  7 2015, 14:10:42) [MSC v.1500 64 bit (AMD64)] on win32
In[1]: l = [0,1,2,3,2,3,1,2,0]
In[2]: m = {0:10, 1:11, 2:12, 3:13}
In[3]: %timeit [m[_] for _ in l]  # list comprehension
1000000 loops, best of 3: 762 ns per loop
In[4]: %timeit map(lambda _: m[_], l)  # using 'map'
1000000 loops, best of 3: 1.66 µs per loop
In[5]: %timeit list(m[_] for _ in l)  # a generator expression passed to a list constructor.
1000000 loops, best of 3: 1.65 µs per loop
In[6]: %timeit map(m.__getitem__, l)
The slowest run took 4.01 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 853 ns per loop
In[7]: %timeit map(m.get, l)
1000000 loops, best of 3: 908 ns per loop
In[33]: from operator import itemgetter
In[34]: %timeit list(itemgetter(*l)(m))
The slowest run took 9.26 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 739 ns per loop

La compréhension de liste et le sélecteur d'objets sont donc les moyens les plus rapides de le faire.

MISE À JOUR: Pour les grandes listes aléatoires et les cartes, j'ai eu des résultats un peu différents:

Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Dec  7 2015, 14:10:42) [MSC v.1500 64 bit (AMD64)] on win32
In[2]: import numpy.random as nprnd
l = nprnd.randint(1000, size=10000)
m = dict([(_, nprnd.rand()) for _ in range(1000)])
from operator import itemgetter
import operator
f = operator.itemgetter(*l)
%timeit f(m)
%timeit list(itemgetter(*l)(m))
%timeit [m[_] for _ in l]  # list comprehension
%timeit map(m.__getitem__, l)
%timeit list(m[_] for _ in l)  # a generator expression passed to a list constructor.
%timeit map(m.get, l)
%timeit map(lambda _: m[_], l)
1000 loops, best of 3: 1.14 ms per loop
1000 loops, best of 3: 1.68 ms per loop
100 loops, best of 3: 2 ms per loop
100 loops, best of 3: 2.05 ms per loop
100 loops, best of 3: 2.19 ms per loop
100 loops, best of 3: 2.53 ms per loop
100 loops, best of 3: 2.9 ms per loop

Donc , dans ce cas , le gagnant est f = operator.itemgetter(*l); f(m)et extérieur clair: map(lambda _: m[_], l).

MISE À JOUR pour Python 3.6.4:

import numpy.random as nprnd
l = nprnd.randint(1000, size=10000)
m = dict([(_, nprnd.rand()) for _ in range(1000)])
from operator import itemgetter
import operator
f = operator.itemgetter(*l)
%timeit f(m)
%timeit list(itemgetter(*l)(m))
%timeit [m[_] for _ in l]  # list comprehension
%timeit list(map(m.__getitem__, l))
%timeit list(m[_] for _ in l)  # a generator expression passed to a list constructor.
%timeit list(map(m.get, l))
%timeit list(map(lambda _: m[_], l)
1.66 ms ± 74.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
2.1 ms ± 93.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.58 ms ± 88.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.36 ms ± 60.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.98 ms ± 142 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.7 ms ± 284 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
3.14 ms ± 62.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Ainsi, les résultats pour Python 3.6.4 sont presque les mêmes.

Sklavit
la source
17

Voici trois façons.

Relever KeyErrorlorsque la clé n'est pas trouvée:

result = [mapping[k] for k in iterable]

Valeurs par défaut des clés manquantes.

result = [mapping.get(k, default_value) for k in iterable]

Ignorer les clés manquantes.

result = [mapping[k] for k in iterable if k in mapping]
OdraEncoded
la source
found_keys = mapping.keys() & iterabledonne TypeError: unsupported operand type(s) for &: 'list' and 'list'sur python 2.7; `found_keys = [key for key in mapping.keys () if key in iterable] fonctionne mieux
NotGaeL
10

Essaye ça:

mydict = {'one': 1, 'two': 2, 'three': 3}
mykeys = ['three', 'one','ten']
newList=[mydict[k] for k in mykeys if k in mydict]
print newList
[3, 1]
Vikram Singh Chandel
la source
7

Essaye ça:

mydict = {'one': 1, 'two': 2, 'three': 3}
mykeys = ['three', 'one'] # if there are many keys, use a set

[mydict[k] for k in mykeys]
=> [3, 1]
Óscar López
la source
@PeterDeGlopper vous êtes confus. items()est préférable, il n'est pas nécessaire d'effectuer une recherche supplémentaire, il n'y a pas d' len(mydict)*len(mykeys)opération ici! (notez que j'utilise un ensemble)
Óscar López
@ ÓscarLópez Oui, vous inspectez chaque élément du dictionnaire. iteritems ne les donne pas tant que vous n'en avez pas besoin, donc cela évite de construire une liste intermédiaire, mais vous exécutez quand même 'k in mykeys' (order len (mykeys), car c'est une liste) pour chaque k dans mydict. Complètement inutilement, par rapport à la compréhension de liste plus simple qui ne fait que passer sur mykeys.
Peter DeGlopper
@ inspectorG4dget @PeterDeGlopper l'opération d'adhésion mykeysest amortie en temps constant, j'utilise un ensemble, pas une liste
Óscar López
2
La conversion de la liste de l'OP en un ensemble la rend au moins linéaire, mais elle est toujours linéaire sur la mauvaise structure de données et perd de l'ordre. Prenons le cas d'un dictionnaire 10k et de 2 clés dans mykeys. Votre solution effectue des tests d'appartenance de 10 000 ensembles, par rapport à deux recherches dans le dictionnaire pour la compréhension de liste simple. En général, il semble prudent de supposer que le nombre de clés sera inférieur au nombre d'éléments du dictionnaire - et si ce n'est pas le cas, votre approche omettra les éléments répétés.
Peter DeGlopper
5
new_dict = {x: v for x, v in mydict.items() if x in mykeys}
Pavel Minenkov
la source
1

Les pandas le font très élégamment, bien que la compréhension des listes soit toujours plus techniquement pythonique. Je n'ai pas le temps de faire une comparaison de vitesse pour le moment (je reviendrai plus tard et je la placerai):

import pandas as pd
mydict = {'one': 1, 'two': 2, 'three': 3}
mykeys = ['three', 'one']
temp_df = pd.DataFrame().append(mydict)
# You can export DataFrames to a number of formats, using a list here. 
temp_df[mykeys].values[0]
# Returns: array([ 3.,  1.])

# If you want a dict then use this instead:
# temp_df[mykeys].to_dict(orient='records')[0]
# Returns: {'one': 1.0, 'three': 3.0}
abby sobh
la source
-1

Ou simplement mydict.keys()c'est un appel de méthode intégré pour les dictionnaires. Explorez également mydict.values()et mydict.items().

// Ah, le poste OP m'a confondu.

Edgar Aroutiounian
la source
5
Les méthodes intégrées sont utiles mais elles ne donnent pas une liste des éléments correspondants à partir d'une liste de clés donnée. Cette réponse n'est pas une réponse correcte à cette question particulière.
stenix
-1

Après la fermeture de Python: moyen efficace de créer une liste à partir de valeurs dict avec un ordre donné

Récupérer les clés sans construire la liste:

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import collections


class DictListProxy(collections.Sequence):
    def __init__(self, klist, kdict, *args, **kwargs):
        super(DictListProxy, self).__init__(*args, **kwargs)
        self.klist = klist
        self.kdict = kdict

    def __len__(self):
        return len(self.klist)

    def __getitem__(self, key):
        return self.kdict[self.klist[key]]


myDict = {'age': 'value1', 'size': 'value2', 'weigth': 'value3'}
order_list = ['age', 'weigth', 'size']

dlp = DictListProxy(order_list, myDict)

print(','.join(dlp))
print()
print(dlp[1])

Le résultat:

value1,value3,value2

value3

Qui correspond à l'ordre donné par la liste

souvenir
la source
-2
reduce(lambda x,y: mydict.get(y) and x.append(mydict[y]) or x, mykeys,[])

au cas où il n'y aurait pas de clés dans dict.

yupbank
la source