One would think doing this is easy. I swear it is, just... I can't seem to figure it out. How do I transform:
terrible_way_to_describe_nested_json=['a.b.c','a.b.d','a.e','a.f','g.h']
into
{
"a": {
"b": {
"c": None,
"d": None
},
"e": None,
"f": None
},
"g": {
"h": None
}
}
If you would consider 'a.b.c'
a path of a deconstructed JSON load, then I have about 200 of these unsorted paths (transformation should work regardless of order) that go up to 8 dots deep all eagerly hoping to become part of their original structure. I've tried approaching this using recursion, pandas to sort leaf nodes from internal ones (ridiculous?), crazy list of lists of dictionaries of lists who knows, even autovivification.
Here's one of 6 partial implementations I've written/abandoned. It goes as far as peeling back the layer of nested keys right before the fringe nodes then I loose my mind. I'd almost recommend ignoring it.
def dot_to_json(dotted_paths):
scope_map=[line.split('.') for line in dotted_paths] #Convert dots list to strings
# Sort and group list of strings according to length of list. longest group is last
b=[]
for index in range(max([len(x) for x in scope_map])+1):
a=[]
for item in scope_map:
if len(item)==index:
a.append(item)
b.append(a)
sorted_nest=[x for x in b if x] # finally group according to list length
#Point AA
# group string list 'prefix' with key:value
child_path=[]
for item in sorted_nest[-1]:
child_path.append([item[:-1],{item[-1]:None}])
# peel back a layer
new_child_path=[]
for scope in scope_map[-2]:
value=None # set value to None if fringe node
for index, path in enumerate(child_path):
if path[0]==scope: # else, save key + value as a value to the new prefix key
value=path[1]
child_path.pop(index) # 'move' this path off child_path list
new_child_path.append([scope[:-1],{scope[-1]:value}])
new_child_path+=child_path
#Point BB...
#Loop in some intelligent way between Point AA and Point BB
return new_child_path
#%%
dotted_json=['a.b.c','a.b.d','a.e','a.f','g.h']
scope_map=dot_to_json(dotted_json)
Here you go:
In [5]: terrible_way_to_describe_nested_json=['a.b.c','a.b.d','a.e','a.f','g.h']
In [6]: terrible_way_to_describe_nested_json = [s.split('.') for s in terrible_way_to_describe_nested_json]
In [7]: data = {}
In [8]: for path in terrible_way_to_describe_nested_json:
....: curr = data
....: for i, node in enumerate(path):
....: if i == len(path) - 1:
....: curr[node] = None
....: else:
....: curr = curr.setdefault(node,{})
....:
In [9]: data
Out[9]: {'a': {'b': {'c': None, 'd': None}, 'e': None, 'f': None}, 'g': {'h': None}}
Now pretty printing using the json module gives:
{
"a": {
"f": null,
"b": {
"d": null,
"c": null
},
"e": null
},
"g": {
"h": null
}
}
Those two should be equivalent but out of order, or at least, printed out of order.