Home > database >  Python - transforming a parent-child dict
Python - transforming a parent-child dict

Time:06-09

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
  • Related