web-dev-qa-db-fra.com

Extraire un sous-ensemble de paires clé-valeur de Python objet du dictionnaire?

J'ai un grand objet dictionnaire qui a plusieurs paires de valeurs clés (environ 16), mais je ne suis intéressé que par 3 d'entre elles. Quel est le meilleur moyen (le plus court/efficace/le plus élégant) d'y parvenir?

Le meilleur que je connaisse est:

bigdict = {'a':1,'b':2,....,'z':26} 
subdict = {'l':bigdict['l'], 'm':bigdict['m'], 'n':bigdict['n']}

Je suis sûr qu'il existe un moyen plus élégant que celui-ci. Des idées?

265
Jayesh

Tu pourrais essayer:

dict((k, bigdict[k]) for k in ('l', 'm', 'n'))

... ou dans Python 3 Python versions 2.7 ou ultérieures (merci à Fábio Diniz pour avoir signalé que cela fonctionne également dans la version 2.7) :

{k: bigdict[k] for k in ('l', 'm', 'n')}

Mise à jour: Comme Håvard S indique, je suppose que vous savez que les clés vont figurer dans le dictionnaire - voir sa réponse = si vous ne pouvez pas faire cette hypothèse. Alternativement, comme timbo indique dans les commentaires, si vous souhaitez qu'une clé manquante dans bigdict soit associée à None, vous pouvez faire:

{k: bigdict.get(k, None) for k in ('l', 'm', 'n')}

Si vous utilisez Python 3, et que vous seulement voulez des clés dans le nouveau dict existant dans le premier, vous peut utiliser le fait de voir les objets implémenter certaines opérations définies:

{k: bigdict[k] for k in bigdict.keys() & {'l', 'm', 'n'}}
366
Mark Longair

Un peu plus court, au moins:

wanted_keys = ['l', 'm', 'n'] # The keys you want
dict((k, bigdict[k]) for k in wanted_keys if k in bigdict)
105
Håvard S
interesting_keys = ('l', 'm', 'n')
subdict = {x: bigdict[x] for x in interesting_keys if x in bigdict}
20
theheadofabroom

Un peu de comparaison de vitesse pour toutes les méthodes mentionnées:

Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Jan 29 2016, 14:26:21) [MSC v.1500 64 bit (AMD64)] on win32
In[2]: import numpy.random as nprnd
keys = nprnd.randint(1000, size=10000)
bigdict = dict([(_, nprnd.Rand()) for _ in range(1000)])

%timeit {key:bigdict[key] for key in keys}
%timeit dict((key, bigdict[key]) for key in keys)
%timeit dict(map(lambda k: (k, bigdict[k]), keys))
%timeit dict(filter(lambda i:i[0] in keys, bigdict.items()))
%timeit {key:value for key, value in bigdict.items() if key in keys}
100 loops, best of 3: 3.09 ms per loop
100 loops, best of 3: 3.72 ms per loop
100 loops, best of 3: 6.63 ms per loop
10 loops, best of 3: 20.3 ms per loop
100 loops, best of 3: 20.6 ms per loop

Comme prévu: la compréhension du dictionnaire est la meilleure option.

14
Sklavit

Cette réponse utilise une compréhension du dictionnaire similaire à la réponse sélectionnée, mais ne sera pas sauf sur un élément manquant.

version python 2:

{k:v for k, v in bigDict.iteritems() if k in ('l', 'm', 'n')}

version python 3:

{k:v for k, v in bigDict.items() if k in ('l', 'm', 'n')}
11
Meow

Peut être:

subdict=dict([(x,bigdict[x]) for x in ['l', 'm', 'n']])

Python 3 prend même en charge les éléments suivants:

subdict={a:bigdict[a] for a in ['l','m','n']}

Notez que vous pouvez vérifier l'existence dans le dictionnaire comme suit:

subdict=dict([(x,bigdict[x]) for x in ['l', 'm', 'n'] if x in bigdict])

resp. pour python 3

subdict={a:bigdict[a] for a in ['l','m','n'] if a in bigdict}
4
phimuemue

D'accord, c'est quelque chose qui m'a dérangé à plusieurs reprises, alors merci Jayesh de l'avoir demandé.

Les réponses ci-dessus semblent être la meilleure solution, mais si vous utilisez tout cela dans votre code, il est logique d'envelopper la fonctionnalité à mon humble avis. En outre, il existe deux cas d'utilisation possibles ici: l'un dans lequel vous voulez savoir si tous les mots clés sont dans le dictionnaire d'origine. et un où vous ne le faites pas. Ce serait bien de traiter les deux à égalité.

Donc, pour mes deux penneth, je suggère d’écrire une sous-classe de dictionnaire, par exemple.

class my_dict(dict):
    def subdict(self, keywords, fragile=False):
        d = {}
        for k in keywords:
            try:
                d[k] = self[k]
            except KeyError:
                if fragile:
                    raise
        return d

Maintenant, vous pouvez sortir un sous-dictionnaire avec

orig_dict.subdict(keywords)

Exemples d'utilisation:

#
## our keywords are letters of the alphabet
keywords = 'abcdefghijklmnopqrstuvwxyz'
#
## our dictionary maps letters to their index
d = my_dict([(k,i) for i,k in enumerate(keywords)])
print('Original dictionary:\n%r\n\n' % (d,))
#
## constructing a sub-dictionary with good keywords
oddkeywords = keywords[::2]
subd = d.subdict(oddkeywords)
print('Dictionary from odd numbered keys:\n%r\n\n' % (subd,))
#
## constructing a sub-dictionary with mixture of good and bad keywords
somebadkeywords = keywords[1::2] + 'A'
try:
    subd2 = d.subdict(somebadkeywords)
    print("We shouldn't see this message")
except KeyError:
    print("subd2 construction fails:")
    print("\toriginal dictionary doesn't contain some keys\n\n")
#
## Trying again with fragile set to false
try:
    subd3 = d.subdict(somebadkeywords, fragile=False)
    print('Dictionary constructed using some bad keys:\n%r\n\n' % (subd3,))
except KeyError:
    print("We shouldn't see this message")

Si vous exécutez tout le code ci-dessus, vous devriez voir (quelque chose comme) la sortie suivante (désolé pour le formatage):

Dictionnaire original:
{'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3, 'g': 6, 'f': 5, 'i ': 8,' h ': 7,' k ': 10,' j ': 9,' m ': 12,' l ': 11,' o ': 14,' n ': 13,' q ': 16, 'p': 15, 's': 18, 'r': 17, 'u': 20, 't': 19, 'w': 22, 'v': 21, 'y': 24, 'x': 23, 'z': 25}

Dictionnaire à partir de clés impaires:
{'a': 0, 'c': 2, 'e': 4, 'g': 6, 'k': 8, 'k': 10, 'm': 12, 'o ': 14,' q ': 16,' s ': 18,' u ': 20,' w ': 22,' y ': 24}

la construction de subd2 échoue:
dictionnaire original ne contient pas certaines clés

Dictionnaire construit en utilisant quelques mauvaises clés:
{'b': 1, 'd': 3, 'f': 5, 'h': 7, 'j': 9, 'l': 11, 'n': 13, 'p ': 15,' r ': 17,' t ': 19,' v ': 21,' x ': 23,' z ': 25}

3
pandamonium

Vous pouvez aussi utiliser la carte (qui est une fonction très utile très utile ):

sd = dict(map(lambda k: (k, l.get(k, None)), l))

Exemple:

large_dictionary = {'a1':123, 'a2':45, 'a3':344} list_of_keys = ['a1', 'a3'] small_dictionary = dict(map(lambda key: (key, large_dictionary.get(key, None)), list_of_keys))

PS J'ai emprunté le .get (clé, aucun) d'une réponse précédente :)

3
halfdanrump

Encore un autre (je préfère la réponse de Mark Longair)

di = {'a':1,'b':2,'c':3}
req = ['a','c','w']
dict([i for i in di.iteritems() if i[0] in di and i[0] in req])
1
georg