2016-05-06 9 views
2

ich ähnliche Fragen wissen bereits vor gefragt worden, aber ich wirklich Probleme mit ihnen für meinen speziellen Fall der Umsetzung:Python Änderungswert in verschachtelten Wörterbuch, wenn die Bedingung erfüllt ist

Lassen Sie uns sagen, dass ich ein Wörterbuch mit unterschiedlichen Tiefen haben, für Beispiel:

dicti = {'files': 
    {'a':{'offset':100, 'start': 0}, 
    'b':{ 
     'c':{'offset':50, 'start':0} 
     'd':{'offset':70, 'start':0} 
     } 
    'e':{ 
     'f':{'offset':80, 'start':0} 
     'g':{'offset':30, 'start':0} 
     'h':{'offset':20, 'start':0} 
     } 
    } 
     } 
    etc... (with a lot more different levels and entries) 

so jetzt will ich eine Kopie dieses Wörterbuch mit im Grunde die gleiche Struktur und Schlüssel, aber wenn 'offset' (auf jeder Ebene) größer ist als die 50'offset' sagen lassen sollte 0

geändert werden

Ich denke, eine Art iterative Funktion wäre die beste, aber ich kann nicht meinen Kopf bekommen ...

+0

Wie sieht Ihre Daten aussehen, bevor sie in Wörterbuch gelesen werden? Vielleicht haben Sie eine bessere Lösung mit Python 'Pandas' Modul. – Abbas

+0

Ja, ich mag meine Daten auch nicht, aber sie wird von einer 'json'-Datei geladen, also kann ich nichts dagegen tun. – wa4557

+0

Es gibt eine Funktion zum Einlesen von 'json' in' pandas' http: //pandas.pydata .org/pandas-docs/stable/generated/pandas.read_json.html Sie erhalten mehr strukturierte Daten, mit denen Sie arbeiten können. – Abbas

Antwort

2

Sie können die Standard-Maschinen für die Kopie verwenden und dann die kopierte Wörterbuch (Lösung # 1 in meinem Beispiel) ändern, oder Sie können in der gleichen Funktion Kopieren und Modifikation tun (Lösung # 2).

In beiden Fällen suchen Sie nach einer rekursiven Funktion.

import copy 
from pprint import pprint 
dicti = {'files': 
    {'a':{'offset':100, 'start': 0}, 
    'b':{ 
     'c':{'offset':50, 'start':0}, 
     'd':{'offset':70, 'start':0}, 
     }, 
    'e':{ 
     'f':{'offset':80, 'start':0}, 
     'g':{'offset':30, 'start':0}, 
     'h':{'offset':20, 'start':0}, 
     } 
    } 
} 

# Solution 1, two passes 
def modify(d): 
    if isinstance(d, dict): 
     if d.get('offset', 0) > 50: 
      d['offset'] = 0 
     for k,v in d.items(): 
      modify(v) 
dictj = copy.deepcopy(dicti) 
modify(dictj) 
pprint(dictj) 

# Solution 2, copy and modify in one pass 
def copy_and_modify(d): 
    if isinstance(d, dict): 
     d2 = {k:copy_and_modify(v) for k,v in d.items()} 
     if d2.get('offset') > 50: 
      d2['offset'] = 0 
     return d2 
    return d 
dictj = copy_and_modify(dicti) 
pprint(dictj) 
+0

Danke ich mag Ihre zweite Lösung, funktioniert wie ein Charme! – wa4557

+0

Beachten Sie, dass Ihre Probe keine 'list' oder' tuple' oder andere iterierbare Objekte enthielt. Wenn Ihre realen Daten dies tun, müssen Sie möglicherweise meine Lösung aktualisieren. –

2

Eine rekursive Lösung wird intuitiver sein. Sie wollen so etwas wie der folgenden Pseudo-Code:

def copy(dict): 
    new_dict = {} 
    for key, value in dict: 
     if value is a dictionary: 
      new_dict[key] = copy(value) 
     else if key == 'offset' and value > 50: 
      new_dict[key] = 0 
     else: 
      new_dict[key] = value 
    return new_dict 
+0

Ist das langsamer als iterative Funktionen im Umgang mit großen Wörterbüchern? – wa4557

+0

'für Schlüssel, Wert in dict:' wird nicht mit einem Wörterbuch arbeiten. Hast du es mit einem Beispielwörterbuch versucht? – Quinn

+0

@ccf Deshalb habe ich gesagt, es ist Pseudocode. Da ich keinen Interpreter oder einen Compiler habe, der Pseudocode ausführen kann (lassen Sie es mich wissen, wenn Sie einen kennen), habe ich es nicht an einem Beispielwörterbuch getestet – amiller27

1
d = {'files': 
    {'a':{'offset':100, 'start': 0}, 
    'b':{ 
     'c':{'offset':50, 'start':0}, 
     'd':{'offset':70, 'start':0} 
     }, 
    'e':{ 
     'f':{'offset':80, 'start':0}, 
     'g':{'offset':30, 'start':0}, 
     'h':{'offset':20, 'start':0} 
     } 
    } 
     } 

def transform(item): 
    new_item = item.copy() # consider usage of deepcopy if needed 
    if new_item['offset'] == 80: 
     new_item['offset'] = 'CHANGED' 
    return new_item 

def visit(item): 
    if item.get('offset'): 
     return transform(item) 
    else: 
     return {k: visit(v) for k, v in item.items()} 

result = visit(d) 
print(result) 

Ausgang:

{ 
    'files': { 
     'b': { 
      'd': { 
       'offset': 70, 
       'start': 0 
      }, 
      'c': { 
       'offset': 50, 
       'start': 0 
      } 
     }, 
     'e': { 
      'g': { 
       'offset': 30, 
       'start': 0 
      }, 
      'h': { 
       'offset': 20, 
       'start': 0 
      }, 
      'f': { 
       'offset': 'CHANGED', 
       'start': 0 
      } 
     }, 
     'a': { 
      'offset': 100, 
      'start': 0 
     } 
    } 
} 

Sie können einige Links in Bezug auf Sachen revidieren, die in der Antwort verwendet wird:

0

Sie könnten eine rekursive Funktion aufrufen, um seinen Wert zu ändern, wenn Bedingung erfüllt ist:

dicti = {'files': 
    {'a':{'offset':100, 'start': 0}, 
    'b':{ 
     'c':{'offset':50, 'start':0}, 
     'd':{'offset':70, 'start':0} 
     }, 
    'e':{ 
     'f':{'offset':80, 'start':0}, 
     'g':{'offset':30, 'start':0}, 
     'h':{'offset':20, 'start':0} 
     } 
    } 
} 


def dictLoop(dt): 
    for k, v in dt.items(): 
     if isinstance(v, int): 
      if k == 'offset' and v > 50: 
       dt[k] = 0 
     else: dictLoop(v) 
    return dt 

print dictLoop(dicti) 
Verwandte Themen