2017-05-01 11 views
1

Ich habe eine JSON Datei, die ziemlich einfach ist (aber wirklich groß) und ich muss es ein wenig filtern. (I haben jetzt jede Python für eine Weile getan ...)Python effiziente Möglichkeit, dict zu filtern

Es sieht wie folgt aus:

{ 
    'entry_1': { 
     'field_1' : 'value', 
     'field_2' : 123, 
     'field_3' : '', 
     'field_4' : 456 
    }, 
    'entry_2': { 
     'field_1' : 'value', 
     'field_2' : 321, 
     'field_3' : 'value', 
     'field_4' : 654 
    }, 
    ... 
} 

Ich möchte es filtern die nutzlosen Felder zu entfernen. Meine Testdatei ist klein, was ich getan habe funktioniert gut, aber ich muss es auf eine ziemlich große Datei tun und ich weiß, dass mein Code ziemlich hässlich ist.

Bisher habe ich dies getan:

dict_in = json.load(INFILE) 
dict_out = defaultdict(dict) #4harambe 

allowed_fields = {'field_1', 'field_3'} 
'''should I use a set or a tuple here ? or maybe something else 
All data inside will be unique (set) but 
those data wont change (tuple) 
''' 

for entry in dict_in: 
    for field in dict_in[entry]: 
     if field in allowed_fields and not dict_in[entry][field]: 
      # allowed field plus non empty string 
      dict_out[entry][field] = dict_in[entry][field] 

Ich mag gerne wissen, wie ich es ein bisschen sexier und effizienter machen können (die Doppel-Loop + if-Anweisung ist ziemlich schlecht zusammen mit der Art und Weise Ich greife auf die Daten zu). Ich habe über itertools gelesen, aber ich weiß noch nicht, wie ich es benutzen soll und ob es eine gute Idee ist.

+1

Lassen Sie es als 'set()' O (1) gegenüber Tupel O (n). Auch von den Antworten unten ist Ihre am besten lesbar und genau die möglicherweise gleiche Leistung. – salparadise

Antwort

0

Man könnte es dictionary comprehensions mit schreiben:

{'entry_1': {'field_1': 'value'}, 
'entry_2': {'field_1': 'value', 'field_3': 'value'}} 
0

Keine Notwendigkeit iterieren der inneren dicts nur die Werte greifen:

allowed_fields = {'field_1', 'field_3'} 
dict_out = { 
    entry_key: { 
     field: field_value 
     for field, field_value in entry_value.items() 
     if field in allowed_fields and field_value 
    } 
    for entry_key, entry_value in dict_in.items() 
} 

die alle field_1 und field_3 Tasten mit nicht leeren Werte gibt direkt:

def grabber(d, fields, default=None): 
    return dict((f, d.get(f, default)) for f in fields) 

dict_out = {k:grabber(v, allowed_fields) for k,v in dict_in.items()} 
2

Nur:

dict_out = {k: {f: v[f] for f in allowed_fields if v.get(f)} 
      for k, v in dict_in.items()} 

Hinweis:

Wenn Sie noch Python sind 2.7, verwenden .iteritems() nicht .items()

+0

Gute Antwort. Ein Vorbehalt: Für Python 2.7 wäre es besser, '.iteritems()' stattdessen zu verwenden, da '.items()' eine separate 'Liste' aller Elemente erstellt - was für große Objekte ziemlich ineffizient ist. In Python 3.x ist das nicht nötig. –

+1

@DanLenski Ich habe hinzugefügt, dass als eine Anmerkung für Landsleute immer noch unter der drückenden Joch von 2,7 – donkopotamus

+0

@ donkopotamus leiden ... kann nicht mit dir dort streiten. Es ist Zeit, zu den alten Minen, die sich in den uralten geheimen Datenbanken befinden, zurückzukehren. –

0

dict_in als eine Eingabe gegeben und fields, die Sie benötigen:

fields = ['field_1', 'field_4'] 
dict_out = dict([(k, {_k: _v for _k, _v in v.items() if _k in fields}) for k, v in dict_in.items()]) 

dict_out wird wie folgt aussehen:

{'entry_1': {'field_1': 'value', 'field_4': 456}, 
'entry_2': {'field_1': 'value', 'field_4': 654}} 
Verwandte Themen