Transform data with level column in python

Question:

I have data like this which represents hierarchical tree structure:

[
    {
        "level":0,
        "name":"python"
    },
    {
        "level":1,
        "name":"food"
    },
    {
        "level":2,
        "name":"banana"
    },
    {
        "level":3,
        "name":"protein"
    },
    {
        "level":2,
        "name":"apple"
    },
    {
        "level":1,
        "name":"fuel"
    }
]

I want to transform it into:

[
    {
        "level":0,
        "name":"python",
        "children":[
            {
                "level":1,
                "name":"food",
                "children":[
                    {
                        "level":2,
                        "name":"banana",
                        "children":[
                            {
                                "level":3,
                                "name":"protein",
                                "children":[
                                    
                                ]
                            }
                        ]
                    },
                    {
                        "level":2,
                        "name":"apple",
                        "children":[
                            
                        ]
                    }
                ]
            },
            {
                "level":1,
                "name":"fuel",
                "children":[
                    
                ]
            }
        ]
    }
]

I am using python and would prefer the solution in python with or without using external libraries, (even using pandas). I would love to see the solutions, thank you in advance 🙂

Asked By: Usman5251

||

Answers:

Here is one way:

def create_tree(nodes):
    # add parent information to each node
    for i, node in enumerate(nodes):
        if node['level'] == 0:
            node['parent'] = None
        else:
            j = i - 1
            while j >= 0:
                if nodes[j]['level'] < node['level']:
                    node['parent'] = nodes[j]['name']
                    break
                j -= 1
    
    
    node_dict = {}
    for node in nodes:
        node_dict[node['name']] = node
    
    for node in nodes:
        parent_name = node.get('parent')
        if parent_name is not None:
            parent = node_dict[parent_name]
            if 'children' not in parent:
                parent['children'] = []
            parent['children'].append(node)
    
    for node in nodes:
        if node.get('parent') is None:
            return node
    return None

nodes = [
    {"level":0,"name":"python"},
    {"level":1,"name":"food"},
    {"level":2,"name":"banana"},
    {"level":3,"name":"protein"},
    {"level":2,"name":"apple"},
    {"level":1,"name":"fuel"}
]

tree = create_tree(nodes)

print(tree)


which gives what you wanted

{'level': 0, 'name': 'python', 'parent': None, 'children': [{'level': 1, 'name': 'food', 'parent': 'python', 'children': [{'level': 2, 'name': 'banana', 'parent': 'food', 'children': [{'level': 3, 'name': 'protein', 'parent': 'banana'}]}, {'level': 2, 'name': 'apple', 'parent': 'food'}]}, {'level': 1, 'name': 'fuel', 'parent': 'python'}]}

I suppose the order of the dictionaries in your list matters, since otherwise I wouldn’t know under which parent the children are supposed to be listed. I would suggest to write a recursive function to get the last element at level n and append the children there:

import json

input_list = [
    {
        "level":0,
        "name":"python"
    },
    {
        "level":1,
        "name":"food"
    },
    {
        "level":2,
        "name":"banana"
    },
    {
        "level":3,
        "name":"protein"
    },
    {
        "level":2,
        "name":"apple"
    },
    {
        "level":1,
        "name":"fuel"
    }
]

def get_last_elt_at_lvl(rec, lvl):
    if lvl == 0:
        return rec[-1]
    else:
        for i in range(len(rec)-1,-1,-1):
            if rec[i]['children']:
                r = get_last_elt_at_lvl(rec[-1]['children'], lvl-1)
                if r:
                    return r
    return None

output_list = []
for d in input_list:
    if d["level"] == 0:
        output_list.append(d)
    else:
        last_elt = get_last_elt_at_lvl(output_list, d["level"]-1)
        children = last_elt.setdefault('children', [])
        children.append(d)

print(json.dumps(output_list, indent=4))

Output:

[
    {
        "level": 0,
        "name": "python",
        "children": [
            {
                "level": 1,
                "name": "food",
                "children": [
                    {
                        "level": 2,
                        "name": "banana",
                        "children": [
                            {
                                "level": 3,
                                "name": "protein"
                            }
                        ]
                    },
                    {
                        "level": 2,
                        "name": "apple"
                    }
                ]
            },
            {
                "level": 1,
                "name": "fuel"
            }
        ]
    }
]
Answered By: Tranbi