Vorwort: Um zu erklären, warum Ich mache das, ich werde das Endziel erklären. Im Wesentlichen habe ich eine Liste von Konten, die in einer sehr spezifischen Syntax definiert sind. Hier sind einige Beispiele:Erstellen Sie einen Baum aus mehreren verschachtelten Wörterbüchern/Listen in Python
Wie oben zu sehen, kann ein Konto beliebig viele Eltern und Kinder haben. Das Endziel besteht darin, die obigen Konten in eine Baumstruktur in Python zu zerlegen, die für die automatische Vervollständigung von Konten im Editor für erhabenes Text verwendet wird (dh wenn ich Assets: eingab und dann für die automatische Vervollständigung abgefragt würde, würde ich mit einer Liste als solche präsentiert werden: Bank, Ersparnisse, reserviert)
das Ergebnis: die Kontoliste aus dem Vorwort Verwendung würde das gewünschte Ergebnis in Python aussieht etwas wie unten:
[
{
"Assets":[
{
"Bank":[
"Car",
"House"
]
},
{
"Savings":[
"Emergency",
{
"Goals":[
"Roof"
]
}
]
},
"Reserved"
]
}
]
Halb-Lösung: Ich wa s sind in der Lage, zwei grundlegende Accounts zu erhalten, die durch Rekursion zusammengefügt werden. Dies funktioniert für das Hinzufügen dieser zwei: Assets:Bank:Car
und Assets:Bank:House
. Sobald sie sich jedoch voneinander zu unterscheiden beginnen, fällt sie auseinander und die Rekursion wird unordentlich, so dass ich mir nicht sicher bin, ob es der beste Weg ist.
import re
def parse_account(account_str):
subs = account_str.split(":")
def separate(subs):
if len(subs) == 1:
return subs
elif len(subs):
return [{subs[0]: separate(subs[1:])}]
return separate(subs)
def merge_dicts(a, b):
# a will be a list with dictionaries and text values and then nested lists/dictionaries/text values
# b will always be a list with ONE dictionary or text value
key = b[0].keys()[0] # this is the dictionary key of the only dictionary in the b list
for item in a: # item is a dictionary or a text value
if isinstance(item, dict): # if item is a dictionary
if key in item:
# Is the value a list with a dict or a list with a text value
if isinstance(b[0][key][0], str):
# Extend the current list with the new value
item[key].extend(b[0][key])
else:
# Recurse to the next child
merge_dicts(item[key], b[0][key])
else:
return a
# Accounts have an "open [name]" syntax for defining them
text = "open Assets:Bank:Car\nopen Assets:Bank:House\nopen Assets:Savings:Emergency\nopen Assets:Savings:Goals:Roof\nopen Assets:Reserved"
EXP = re.compile("open (.*)")
accounts = EXP.findall(text) # This grabs all accounts
# Create a list of all the parsed accounts
dicts = []
for account in accounts:
dicts.append(parse_account(account))
# Attempt to merge two accounts together
final = merge_dicts(dicts[0], dicts[1])
print final
# In the future we would call: reduce(merge_dicts, dicts) to merge all accounts
Ich könnte das völlig falsch machen und würde mich für unterschiedliche Meinungen interessieren. Hat jemand sonst einen Einblick, wie dies mit den verbleibenden Konten in der Beispielzeichenfolge funktioniert?
Du bist gewünschten Ausgang würde einen 'SyntaxError' (' Reserved' ist ein Schlüssel ohne Wert). – mgilson
Ich entschuldige mich, ich habe die Ausgabe eingefügt: 'print json.dumps (final)', um es besser erkennbar zu machen. –