saif islam
saif islam

Reputation: 57

Group and Nested Group for python

I have some data like this,

menu_list = [
   {'name':'ABC','parent_id':None,'id':5},
   {'name':'XYZ','parent_id':5,'id':7},
   {'name':'APPLE','parent_id':7,'id':8},
   {'name':'Mango','parent_id':5,'id':9},
   {'name':'Mango-small','parent_id':9,'id':10},
]

i was expecting the final group by result like,

ABC
----XYZ
-------- APPLE
----Mango
     ----Mango SMALL

The final output as a dictionary.

I have used collection module of Python, and defaultdict() method. but this do the task only for first level group. But i need the nested and outer both as well. If any suggestion that would be great help. Thanks.

Upvotes: 0

Views: 114

Answers (3)

Dmitriy Neledva
Dmitriy Neledva

Reputation: 864

you can use recursive function to solve this problem.

menu_list = [

   {'name':'ABC','parent_id':None,'id':5},
   {'name':'XYZ','parent_id':5,'id':7},
   {'name':'APPLE','parent_id':7,'id':8},
   {'name':'Mango','parent_id':5,'id':9},
   {'name':'Mango-small','parent_id':9,'id':10},
]


def rec_somehing(d:dict,par_id:int,depth:int)->str:
    for i in d:
        if i['parent_id'] == par_id:
            print('....'*depth,i['name'])   
            rec_somehing(d,i['id'],depth+1)

rec_somehing(menu_list,None,1)

#output:
# .... ABC
# ........ XYZ
# ............ APPLE
# ........ Mango
# ............ Mango-small

If you want to get something like {'ABC': {'XYZ': 'APPLE', 'Mango': 'Mango-small'}} you can use something like this

menu_list = [
   {'name':'ABC','parent_id':None,'id':5},
   {'name':'XYZ','parent_id':5,'id':7},
   {'name':'APPLE','parent_id':7,'id':8},
   {'name':'Mango','parent_id':5,'id':9},
   {'name':'Mango-small','parent_id':9,'id':10},
]


new_dict = {}

def rec_somehing(d:dict,par_id:int,depth)->None:
    if not depth:
        for i in d:
            if i['parent_id'] == par_id:
                new_dict[i['name']] = {}
                rec_somehing(d,i['id'],1)
    else:
        for i in d:
            if i['parent_id'] == par_id:
                for j in d:
                    if j['parent_id'] == i['id']:
                        if new_dict.get(list(new_dict.keys())[0]).get(i['name']) != j['name']:
                            new_dict[list(new_dict.keys())[0]][i['name']] = j['name'] 
                            rec_somehing(d,i['id'],1)  

rec_somehing(menu_list,None,0)

print(new_dict)

#output: {'ABC': {'XYZ': 'APPLE', 'Mango': 'Mango-small'}}

if you're gonna input the same type of data -> [list with dicts of 3 items] it will be working, but if you input something else (like [list of dicts of dicts of dicts... etc]) it won't.

Upvotes: 2

R. Baraiya
R. Baraiya

Reputation: 1530

Code:

import re

ls = [
   {'name':'ABC','parent_id':None,'id':5},
   {'name':'XYZ','parent_id':5,'id':7},
   {'name':'APPLE','parent_id':7,'id':8},
   {'name':'Mango','parent_id':5,'id':9},
   {'name':'Mango-small','parent_id':9,'id':10},
]

#creating new dict by id and name only
id_nm = {l['id']:l['name'] for l in ls}                      #Output: {5: 'ABC', 7: 'XYZ', 8: 'APPLE', 9: 'Mango', 10: 'Mango-small'}


#Another new dict by parent and child
dic = {i:[]for i in [l['parent_id']for l in ls]}   
[dic[l['parent_id']].append(l['id']) for l in ls]            #Output: {None: [5], 5: [7, 9], 7: [8], 9: [10]}

#Another new dict with parent with most child
nd = [{id_nm[k]:v} for k,v in dic.items() if len(v)>1][0]    #Output: {'ABC': [7, 9]}


#Here loop to child list of nd, to findout the grad child/ meanwhile also replace the ids with name using above `id_nm` dict
for ls in nd.values():
    for i,l in enumerate(ls):
        ls[i]={id_nm[l]:id_nm[dic[l][0]]}
nd

Output:

{'ABC': [{'XYZ': 'APPLE'}, {'Mango': 'Mango-small'}]}

Upvotes: 1

treuss
treuss

Reputation: 2388

Instead of fiddling with IDs, you could just organize your data the way you want it. Example:

menu_list = [
   {'name': 'ABC', 'children': [
       {'name': 'XYZ', 'children': [
           {'name': 'APPLE', 'children': []}
       ]},
       {'name': 'Mango', 'children': [
           {'name': 'Mango-small', 'children': []}
       ]}
   ]}
]

Upvotes: 0

Related Questions