Moe Sam
Moe Sam

Reputation: 63

How to flatten some levels of nested dictionary?

I have nested dictionary d as below

d = {'id': {"a,b": {'id': {"x": {'id': None},
                           "y": {'id': {"a": {'id': None},
                                        "b": {'id': None}}}}},
            "c,d": {'id': {"c": {'id': None},
                            "d": {'id': {"x": {'id': None},
                                         "y": {'id': None}}}}}}}

and would like unnest some levels and compress it to the following output:

{"a,b": {"x": None,
         "y": {"a": None,
               "b": None}},
 "c,d": {"c": None,
         "d": {"x": None,
               "y": None}}}

Would like to unnest any nested dictionary with the key id and replace it with the inner dictionary

My starting point is:

def unnest_dictionary(d):
    for k,v in d.items():
        if isinstance(v, dict):
            unnest_dictionary(v)
        if k=='id':
            ......

Not sure how to unnest it from there

Upvotes: 0

Views: 136

Answers (1)

Moe Sam
Moe Sam

Reputation: 63

Here is how i ended up solving for it

I flattened the dictionary, removed the levels with id then nested it back again

import re

d = {'id': {"a,b": {'id': {"x": {'id': None},
                           "y": {'id': {"a": {'id': None},
                                        "b": {'id': None}}}}},
            "c,d": {'id': {"c": {'id': None},
                            "d": {'id': {"x": {'id': None},
                                         "y": {'id': None}}}}}}}


def flatten_dict(dd, separator ='_', prefix =''): 
    return { prefix + separator + k if prefix else k : v 
             for kk, vv in dd.items() 
             for k, v in flatten_dict(vv, separator, kk).items() 
             } if isinstance(dd, dict) else { prefix : dd }

def nest_dict(dict1): 
    result = {} 
    for k, v in dict1.items(): 

        split_rec(k, v, result) 
    return result 

def split_rec(k, v, out): 

    k, *rest = k.split('_', 1) 
    if rest: 
        split_rec(rest[0], v, out.setdefault(k, {})) 
    else: 
        out[k] = v  

flat_d = flatten_dict(d)
for k in list(flat_d.keys()):
    new_key = re.sub(r'_id|id_','',k)
    flat_d[new_key] = flat_d.pop(k)
nested_d = nest_dict(flat_d)

print(nested_d)
# {'a,b': {'x': None, 'y': {'a': None, 'b': None}}, 'c,d': {'c': None, 'd': {'x': None, 'y': None}}}

Upvotes: 1

Related Questions