2009-07-31 7 views
5

Ok, je suis coincé, besoin d'aide à partir d'ici ...Filtrer les dictionnaires et créer des sous-dictionnaires basés sur des clés/valeurs en Python?

Si j'ai un dictionnaire principal comme ceci:

data = [ {"key1": "value1", "key2": "value2", "key1": "value3"}, 
{"key1": "value4", "key2": "value5", "key1": "value6"}, 
{"key1": "value1", "key2": "value8", "key1": "value9"} ] 

Maintenant, je dois passer par ce dictionnaire déjà pour mettre en forme certaines des données, à savoir:

for datadict in data: 
    for key, value in datadict.items(): 
    ...filter the data... 

maintenant, comment pourrais-je dans cette même boucle d'une certaine manière (si possible ... sinon, proposer des alternatives s'il vous plaît) vérifier les valeurs de certaines touches, et si ces valeurs correspondre à mes préréglages alors je voudrais ajouter cette liste entière à un autre dictionnaire, donc effec Créer des dictionnaires plus petits en partant de ce dictionnaire principal basé sur certaines clés et valeurs?

Alors, disons que je veux créer un sous-dictionnaire avec toutes les listes dans lesquelles key1 a une valeur de « valeur1 », qui, pour la liste ci-dessus me donnerait quelque chose comme ceci:

subdata = [ {"key1": "value1", "key2": "value2", "key1": "value3"}, 
{"key1": "value1", "key2": "value8", "key1": "value9"} ] 
+1

"un dictionnaire principal comme celui-ci" n'est pas correct. Vous avez une liste de dictionnaires. –

+0

Et les clés de dictionnaire sont uniques, donc vous ne pouvez pas construire un dictionnaire avec des clés dupliquées comme ça: {"key1": "value1", "key2": "value2", "key1": "value3"}; le résultat est {'key2': 'value2', 'key1': 'value3'}. Si vous voulez vraiment les doublons, vous aurez besoin d'une liste, donc la structure globale serait une liste de listes ou les valeurs du dictionnaire devraient être des tuples ou des listes. –

Répondre

9

Voici une façon pas si jolie de le faire. Le résultat est un générateur, mais si vous voulez vraiment une liste, vous pouvez l'entourer avec un appel à list(). Généralement, cela n'a pas d'importance.

Le prédicat est une fonction qui décide pour chaque couple clé/valeur si un dictionnaire de la liste va le couper. Celui par défaut accepte tout. Si aucune paire k/v dans le dictionnaire ne correspond, elle est rejetée.

def filter_data(data, predicate=lambda k, v: True): 
    for d in data: 
     for k, v in d.items(): 
       if predicate(k, v): 
        yield d 


test_data = [{"key1":"value1", "key2":"value2"}, {"key1":"blabla"}, {"key1":"value1", "eh":"uh"}] 
list(filter_data(test_data, lambda k, v: k == "key1" and v == "value1")) 
# [{'key2': 'value2', 'key1': 'value1'}, {'key1': 'value1', 'eh': 'uh'}] 
+2

"pas si jolie"? Être en désaccord. C'est très gentil. –

+0

Merci :). J'ai tendance à penser que les fonctions de l'escalier sont moche. – Skurmedel

+1

@Skurmedel: Votre fonction est élégante et il est facile de voir comment elle fait le travail en quelques étapes simples; Cela évite aux lecteurs d'avoir à analyser une seule ligne compliquée dans leur tête. –

1

Le la réponse est trop simple, donc je suppose que nous manquons des informations. Quoi qu'il en soit:

result = [] 
for datadict in data: 
    for key, value in datadict.items(): 
     thefiltering() 

    if datadict.get('matchkey') == 'matchvalue': 
     result.append(datadict) 

Aussi, vous "dictionnaire principal" n'est pas un dictionnaire mais une liste. Je voulais juste éclaircir ça.

3

Net des questions déjà fait dans d'autres commentaires et réponses (plusieurs clés identiques ne peuvent pas être dans un dict, etc etc), voici comment je le ferais:

def select_sublist(list_of_dicts, **kwargs): 
    return [d for d in list_of_dicts 
      if all(d.get(k)==kwargs[k] for k in kwargs)] 

subdata = select_sublist(data, key1='value1') 
0

Inspiré par la réponse de Skurmedal, je l'ai divisé en un schéma récursif pour travailler avec une base de données de dictionnaires imbriqués. Dans ce cas, un "enregistrement" est le sous-dictionnaire sur le tronc. Le prédicat définit les enregistrements que nous recherchons - ceux qui correspondent à une paire (clé, valeur) dans laquelle ces paires peuvent être profondément imbriquées.

def filter_dict(the_dict, predicate=lambda k, v: True): 
    for k, v in the_dict.iteritems(): 
     if isinstance(v, dict) and _filter_dict_sub(predicate, v): 
      yield k, v 

def _filter_dict_sub(predicate, the_dict): 
    for k, v in the_dict.iteritems(): 
     if isinstance(v, dict) and filter_dict_sub(predicate, v): 
      return True 
     if predicate(k, v): 
      return True 
    return False 

Puisque c'est un générateur, vous devrez peut-être envelopper avec dict(filter_dict(the_dict)) pour obtenir un dictionnaire filtré.

0

Il est une vieille question, mais pour une raison quelconque il n'y a pas de réponse de la syntaxe d'une doublure:

{ k: v for k, v in <SOURCE_DICTIONARY>.iteritems() if <CONDITION> } 

Par exemple:

src_dict = { 1: 'a', 2: 'b', 3: 'c', 4: 'd' } 
predicate = lambda k, v: k % 2 == 0 
filtered_dict = { k: v for k, v in src_dict.iteritems() if predicate(k, v) } 

print "Source dictionary:", src_dict 
print "Filtered dictionary:", filtered_dict 

produira la sortie suivante:

Source dictionary: {1: 'a', 2: 'b', 3: 'c', 4: 'd'} 
Filtered dictionary: {2: 'b', 4: 'd'} 
Questions connexes