I have a python dict like so that represents a parent-child relationship.
{'children': [{'child': {'name': 'chi1', 'parents': 'par', 'foo1': 'bar1'}}, {'child': {'name': 'chi2', 'parents': 'par', 'foo7': 'bar7'}}, {'child': {'name': 'chi1_chi1', 'parents': 'chi1', 'foo2': 'bar2', 'children': [{'child': {'name': 'chi1_chi1_chil1', 'foo3': 'bar3'}}, {'child': {'name': 'chi1_chi1_chi2', 'foo4': 'bar4'}}]}}, {'child': {'name': 'par', 'foo5': 'bar5'}}, {'child': {'name': 'chi1_chi2', 'parents': 'chi1, chi2', 'foo6': 'bar6'}}]}
Input Dict (show in YAML format):
children:
- child:
name: chi1
parents: par
foo1: bar1
- child:
name: chi2
parents: par
foo7: bar7
- child:
name: chi1_chi1
parents: chi1
foo2: bar2
children:
- child:
name: chi1_chi1_chil1
foo3: bar3
- child:
name: chi1_chi1_chi2
foo4: bar4
- child:
name: par
foo5: bar5
- child:
name: chi1_chi2
parents: chi1, chi2 # yay, I have two parents
foo6: bar6
How do I transform it into a tree-like dict which shows the proper parent-child relationship such that I can get all the children of a parent given the parent's name.
{'children': [{'child': {'name': 'par', 'foo5': 'bar5', 'children': [{'child': {'name': 'chi2', 'foo7': 'bar7', 'parents': 'par', 'children': [{'child': {'name': 'chi1_ch2', 'foo6': 'bar6', 'parents': 'chi1, chi2'}}]}}, {'child': {'name': 'chi1', 'foo1': 'bar1', 'parents': 'par', 'children': [{'child': {'name': 'chi1_chi1', 'foo2': 'bar2', 'parents': 'chi1', 'children': [{'child': {'name': 'chi1_chi1_chi1', 'foo3': 'bar3', 'parents': 'chi1_chi1'}}, {'child': {'name': 'chi1_chi1_chi2', 'foo4': 'bar4', 'parents': 'chi1_chi1'}}]}}, {'child': {'name': 'chi1_chi2', 'parents': 'chi1', 'foo6': 'bar6'}}]}}]}}]}
.
Expected result dict (show in YAML format):
children:
- child:
name: par
foo5: bar5
children:
- child:
name: chi2
foo7: bar7
parents: par
children:
- child:
name: chi1_ch2
foo6: bar6
parents: chi1, chi2
- child:
name: chi1
foo1: bar1
parents: par
children:
- child:
name: chi1_chi1
foo2: bar2
parents: chi1
children:
- child:
name: chi1_chi1_chi1
foo3: bar3
parents: chi1_chi1
- child:
name: chi1_chi1_chi2
foo4: bar4
parents: chi1_chi1
- child:
name: chi1_chi2
parents: chi1
foo6: bar6
I've been struggling by creating with this for a couple of days to no avail. I'm not sure how to do this programmatically if there are so many levels. Please help. Thanks in advance!
CodePudding user response:
You can use recursion:
import yaml
data = {'children': [{'child': {'name': 'chi1', 'parents': 'par', 'foo1': 'bar1'}}, {'child': {'name': 'chi2', 'parents': 'par', 'foo7': 'bar7'}}, {'child': {'name': 'chi1_chi1', 'parents': 'chi1', 'foo2': 'bar2', 'children': [{'child': {'name': 'chi1_chi1_chil1', 'foo3': 'bar3'}}, {'child': {'name': 'chi1_chi1_chi2', 'foo4': 'bar4'}}]}}, {'child': {'name': 'par', 'foo5': 'bar5'}}, {'child': {'name': 'chi1_chi2', 'parents': 'chi1, chi2', 'foo6': 'bar6'}}]}
def check_children(node):
if not node['children']:
del node['children']
return node
def build_tree(nodes, parent = ''):
return {'children':[{'child':check_children({**i, 'children':i.get('children', []) build_tree(nodes, i['name'])['children']})}
for i in nodes if parent in i.get('parents', '').split(', ')]}
result = build_tree([i['child'] for i in data['children']])
print(yaml.dump(result))
Output
children:
- child:
children:
- child:
children:
- child:
children:
- child:
foo3: bar3
name: chi1_chi1_chil1
- child:
foo4: bar4
name: chi1_chi1_chi2
foo2: bar2
name: chi1_chi1
parents: chi1
- child:
foo6: bar6
name: chi1_chi2
parents: chi1, chi2
foo1: bar1
name: chi1
parents: par
- child:
children:
- child:
foo6: bar6
name: chi1_chi2
parents: chi1, chi2
foo7: bar7
name: chi2
parents: par
foo5: bar5
name: par