filtrer les éléments dans un dictionnaire python où les clés contiennent une chaîne spécifique

je suis un codeur C développant quelque chose en python. Je sais faire ce qui suit en C (et donc dans la logique de type C appliquée à python), mais je me demande Quelle est la façon de faire "Python".

j'ai un dictionnaire d, et je voudrais opérer sur un sous-ensemble des éléments, seulement ceux qui la clé de who's (chaîne) contient un substrat spécifique.

c'est à dire le C logique serait:

for key in d:
    if filter_string in key:
        # do something
    else
        # do nothing, continue

j'imagine que la version python serait quelque chose comme

filtered_dict = crazy_python_syntax(d, substring)
for key,value in filtered_dict.iteritems():
    # do something

j'ai trouvé beaucoup de messages sur ce site concernant les dictionnaires de filtrage, mais je n'ai pas pu en trouver un qui impliquait exactement ceci.

Mon dictionnaire n'est pas imbriqué et j'utilise python 2.7

61
demandé sur memo 2014-05-26 07:46:05

5 réponses

Que Diriez-vous d'un dict compréhension :

filtered_dict = {k:v for k,v in d.iteritems() if filter_string in k}

celui que vous voyez, il devrait être explicite, comme il se lit comme l'anglais assez bien.

cette syntaxe nécessite Python 2.7 ou plus.

en Python 3, Il n'y a que dict.items() , pas iteritems() donc vous utiliseriez:

filtered_dict = {k:v for (k,v) in d.items() if filter_string in k}
124
répondu Jonathon Reinhart 2016-06-30 16:25:00

choisissez ce qui est le plus lisible et facile à entretenir. Juste parce que vous pouvez l'écrire en une seule ligne ne signifie pas que vous devriez. Votre solution existante est proche de ce que j'utiliserais si ce n'était que j'utiliserais des itéritems pour sauter la recherche de valeur, et je déteste les ifs imbriqués si je peux les éviter:

for key, val in d.iteritems():
    if filter_string not in key:
        continue
    # do something

cependant si vous voulez vraiment quelque chose pour vous laisser itérer à travers un DCT filtré alors je ne ferais pas le processus en deux étapes de la construction du filtre dict puis itération à travers elle, mais à la place utiliser un générateur, parce que ce qui est plus pythonique (et génial) qu'un générateur?

nous créons D'abord notre générateur, et la bonne conception nous dicte de le rendre assez abstrait pour être réutilisable:

# The implementation of my generator may look vaguely familiar, no?
def filter_dict(d, filter_string):
    for key, val in d.iteritems():
        if filter_string not in key:
            continue
        yield key, val

et ensuite nous pouvons utiliser le générateur pour résoudre votre problème gentiment et proprement avec un code simple et compréhensible:

for key, val in filter_dict(d, some_string):
    # do something

en bref: les générateurs sont géniaux.

13
répondu Brendan F 2014-05-26 04:14:40
input = {"A":"a", "B":"b", "C":"c"}
output = {k:v for (k,v) in input.items() if key_satifies_condition(k)}
8
répondu jspurim 2014-05-26 03:54:45

Jonathon vous a donné une approche en utilisant des interprétations dict dans sa réponse . Voici une approche qui traite de votre faire quelque chose partie.

si vous voulez faire quelque chose avec les valeurs du dictionnaire, vous n'avez pas besoin d'une compréhension de dictionnaire du tout:

j'utilise iteritems( ) puisque vous avez étiqueté votre question avec

results = map(some_function, [(k,v) for k,v in a_dict.iteritems() if 'foo' in k])

Maintenant, le résultat sera une liste avec some_function appliqué à chaque paire clé/valeur du dictionnaire, qui a foo dans sa clé.

si vous voulez juste traiter avec les valeurs et ignorer les clés, il suffit de changer la compréhension de la liste:

results = map(some_function, [v for k,v in a_dict.iteritems() if 'foo' in k])

some_function peut être n'importe quel appelable, de sorte qu'un lambda fonctionnerait ainsi:

results = map(lambda x: x*2, [v for k,v in a_dict.iteritems() if 'foo' in k])

la liste intérieure n'est pas requis, car vous pouvez passer un expression génératrice pour map ainsi:

>>> map(lambda a: a[0]*a[1], ((k,v) for k,v in {2:2, 3:2}.iteritems() if k == 2))
[4]
7
répondu Burhan Khalid 2017-05-23 11:54:17