2009-07-31 6 views
5

Ok, mi sono bloccato, bisogno di aiuto da qui in ...Filtraggio di dizionari e creazione di sottodiretti basati su chiavi/valori in Python?

Se ho un dizionario principale in questo modo:

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

Ora, ho bisogno di passare attraverso quel dizionario già per formattare alcuni dei dati, vale a dire:

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

Ora, come faccio in quello stesso ciclo in qualche modo (se possibile ... se non, suggerire alternative per favore) verificare la presenza di valori di alcuni tasti, e se quei valori abbinare i miei preset quindi vorrei aggiungere l'intera lista a un altro dizionario, quindi efficace creare piccoli dizionari mentre esco da questo dizionario principale basato su determinati valori e chiavi?

Quindi, diciamo che voglio creare un sub-dizionario con tutte le liste in cui key1 ha valore di "value1", che per la lista di cui sopra mi avrebbe dato qualcosa di simile:

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

"un dizionario principale come questo" non è corretto. Hai una lista di dizionari. –

+0

E le chiavi del dizionario sono univoche, quindi non è possibile costruire un dizionario con chiavi duplicate del tipo: {"key1": "value1", "key2": "value2", "key1": "value3"}; il risultato è {'key2': 'value2', 'key1': 'value3'}. Se vuoi davvero i duplicati, avrai bisogno di un elenco, quindi la struttura generale sarebbe un elenco di elenchi o i valori del dizionario dovrebbero essere tuple o elenchi. –

risposta

9

Ecco un modo non molto carino di farlo. Il risultato è un generatore, ma se vuoi davvero un elenco puoi circondarlo con una chiamata a list(). Principalmente non importa.

Il predicato è una funzione che decide per ogni coppia chiave/valore se un dizionario della lista sta per tagliarlo. Quello predefinito accetta tutto. Se nessuna coppia k/v nel dizionario corrisponde, viene rifiutata.

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

"non così carino"? Disaccordo. Questo è molto carino. –

+0

Grazie :). Tendo a pensare che le funzioni delle scale come quelle siano brutte. – Skurmedel

+1

@Skurmedel: la tua funzione è elegante ed è facile vedere come fa il lavoro in semplici passaggi; risparmia ai lettori la necessità di analizzare un complicato one-liner nelle loro teste. –

1

Il la risposta è troppo semplice, quindi suppongo che manchino alcune informazioni. Ad ogni modo:

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

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

Inoltre, il "dizionario principale" non è un dizionario ma un elenco. Volevo solo chiarire questo.

3

netto delle questioni già sottolineato in altri commenti e risposte (più tasti identici non possono essere in un dizionario, ecc ecc), ecco come lo farei:

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

Ispirato alla risposta di Skurmedal, ho diviso questo in uno schema ricorsivo per lavorare con un database di dizionari nidificati. In questo caso, un "record" è il subdictionary nel bagagliaio. Il predicato definisce i record che cerchiamo - quelli che corrispondono ad una coppia (chiave, valore) in cui queste coppie possono essere profondamente annidate.

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 

Poiché si tratta di un generatore, potrebbe essere necessario avvolgere con dict(filter_dict(the_dict)) per ottenere un dizionario filtrato.

0

Si tratta di una vecchia questione, ma per qualche motivo non v'è alcun one-liner sintassi risposta:

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

Ad esempio:

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 

produrrà il seguente output:

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