web-dev-qa-db-fra.com

Filtre dict pour ne contenir que certaines clés?

J'ai un dict qui a tout un tas d'entrées. Je ne m'intéresse qu'à quelques-uns d'entre eux. Existe-t-il un moyen facile d'élaguer tous les autres?

400
mpen

Construire un nouveau dict:

dict_you_want = { your_key: old_dict[your_key] for your_key in your_keys }

Utilise la compréhension du dictionnaire.

Si vous utilisez une version qui en manque (par exemple, Python 2.6 et versions antérieures), définissez-la dict((your_key, old_dict[your_key]) for ...). C'est la même chose, mais plus laid.

Notez que ceci, contrairement à la version de jnnnnn, a des performances stables (dépend uniquement du nombre de your_keys) pour old_dicts de toute taille. Tant en termes de vitesse et de mémoire. S'agissant d'une expression génératrice, il traite un élément à la fois et ne recherche pas dans tous les éléments de old_dict.

Tout enlever en place:

unwanted = set(keys) - set(your_dict)
for unwanted_key in unwanted: del your_dict[unwanted_key]
532
user395760

Compréhension légèrement plus élégante de dict:

foodict = {k: v for k, v in mydict.items() if k.startswith('foo')}
89
ransford

Voici un exemple dans python 2.6:

>>> a = {1:1, 2:2, 3:3}
>>> dict((key,value) for key, value in a.iteritems() if key == 1)
{1: 1}

La partie filtrante est l'instruction if.

Cette méthode est plus lente que la réponse de delnan si vous souhaitez uniquement sélectionner quelques-unes des très nombreuses clés.

63
jnnnnn

Vous pouvez le faire avec projet fonction de ma bibliothèque funcy :

from funcy import project
small_dict = project(big_dict, keys)

Regardez aussi select_keys .

19
Suor

Code 1:

dict = { key: key * 10 for key in range(0, 100) }
d1 = {}
for key, value in dict.items():
    if key % 2 == 0:
        d1[key] = value

Code 2:

dict = { key: key * 10 for key in range(0, 100) }
d2 = {key: value for key, value in dict.items() if key % 2 == 0}

Code 3:

dict = { key: key * 10 for key in range(0, 100) }
d3 = { key: dict[key] for key in dict.keys() if key % 2 == 0}

Toutes les performances de code décomposées sont mesurées avec timeit en utilisant number = 1000, et collectées 1000 fois pour chaque morceau de code.

enter image description here

Pour python 3.6, les performances de trois manières de filtrer les clés de dictée sont quasiment identiques. Pour python 2.7 le code 3 est légèrement plus rapide.

17
Y.Y

Cette ligne lambda devrait fonctionner:

dictfilt = lambda x, y: dict([ (i,x[i]) for i in x if i in set(y) ])

Voici un exemple:

my_dict = {"a":1,"b":2,"c":3,"d":4}
wanted_keys = ("c","d")

# run it
In [10]: dictfilt(my_dict, wanted_keys)
Out[10]: {'c': 3, 'd': 4}

Il s’agit d’une compréhension de base de la liste qui parcourt vos clés dict (i dans x) et génère une liste de paires de clés (clé, valeur) si la clé réside dans la liste de clés souhaitée (y). Dict () encapsule le tout pour le sortir en tant qu'objet dict.

17
Jim

Étant donné votre dictionnaire d'origine orig et l'ensemble des entrées qui vous intéressent keys:

filtered = dict(Zip(keys, [orig[k] for k in keys]))

ce qui n'est pas aussi agréable que la réponse de delnan, mais devrait fonctionner dans toutes les versions Python qui vous intéressent. Il est toutefois fragile à chaque élément de keys existant dans votre dictionnaire d'origine.

14
Kai

Sur la base de la réponse acceptée par Delnan.

Et si l'une de vos clés recherchées ne se trouvait pas dans old_dict? La solution delnan lève une exception KeyError que vous pouvez intercepter. Si ce n'est pas ce dont vous avez besoin, vous voudrez peut-être:

  1. n'incluez que les clés qui existent dans old_dict et dans votre ensemble de wanted_keys.

    old_dict = {'name':"Foobar", 'baz':42}
    wanted_keys = ['name', 'age']
    new_dict = {k: old_dict[k] for k in set(wanted_keys) & set(old_dict.keys())}
    
    >>> new_dict
    {'name': 'Foobar'}
    
  2. avoir une valeur par défaut pour les clés qui n'est pas définie dans old_dict.

    default = None
    new_dict = {k: old_dict[k] if k in old_dict else default for k in wanted_keys}
    
    >>> new_dict
    {'age': None, 'name': 'Foobar'}
    
6
MyGGaN

Cette fonction fera l'affaire:

def include_keys(dictionary, keys):
    """Filters a dict by only including certain keys."""
    key_set = set(keys) & set(dictionary.keys())
    return {key: dictionary[key] for key in key_set}

Tout comme la version de delnan, celle-ci utilise la compréhension du dictionnaire et a des performances stables pour les grands dictionnaires (dépend uniquement du nombre de clés que vous autorisez, et non du nombre total de clés dans le dictionnaire).

Et tout comme la version de MyGGan, celle-ci permet à votre liste de clés d'inclure des clés qui peuvent ne pas exister dans le dictionnaire.

Et en bonus, voici l'inverse, où vous pouvez créer un dictionnaire en excluant certaines clés de l'original:

def exclude_keys(dictionary, keys):
    """Filters a dict by excluding certain keys."""
    key_set = set(dictionary.keys()) - set(keys)
    return {key: dictionary[key] for key in key_set}

Notez que contrairement à la version de delnan, l'opération n'est pas effectuée sur place, donc les performances sont liées au nombre de clés dans le dictionnaire. Cependant, l’avantage de cela est que la fonction ne modifiera pas le dictionnaire fourni.

Edit: Ajout d'une fonction séparée pour exclure certaines clés d'un dict.

6
Ryan

Une autre option:

content = dict(k1='foo', k2='nope', k3='bar')
selection = ['k1', 'k3']
filtered = filter(lambda i: i[0] in selection, content.items())

Mais vous obtenez un list (Python 2) ou un itérateur (Python 3) renvoyé par filter(), pas un dict.

2
marsl

forme courte:

[s.pop(k) for k in list(s.keys()) if k not in keep]

Comme la plupart des réponses le suggèrent pour maintenir la concision, nous devons créer un objet en double, qu'il s'agisse d'un objet list ou dict. Celui-ci crée un jetable list mais supprime les clés de l'original dict.

1
nehemiah

Si nous voulons créer un nouveau dictionnaire avec les clés sélectionnées supprimées, nous pouvons utiliser la compréhension du dictionnaire
Par exemple:

d = {
'a' : 1,
'b' : 2,
'c' : 3
}
x = {key:d[key] for key in d.keys() - {'c', 'e'}} # Python 3
y = {key:d[key] for key in set(d.keys()) - {'c', 'e'}} # Python 2.*
# x is {'a': 1, 'b': 2}
# y is {'a': 1, 'b': 2}
1
Srivastava

Voici une autre méthode simple utilisant del dans un liner:

for key in e_keys: del your_dict[key]

e_keys est la liste des clés à exclure. Il mettra à jour votre dict plutôt que de vous en donner un nouveau.

Si vous voulez un nouveau dict de sortie, faites-en une copie avant de supprimer:

new_dict = your_dict.copy()           #Making copy of dict

for key in e_keys: del new_dict[key]
0
Black Thunder