Creating a nested dictionary from a flattened dictionary

  • A+

I have a flattened dictionary which I want to make into a nested one, of the form

flat = {'X_a_one': 10,         'X_a_two': 20,          'X_b_one': 10,         'X_b_two': 20,          'Y_a_one': 10,         'Y_a_two': 20,         'Y_b_one': 10,         'Y_b_two': 20} 

I want to convert it to the form

nested = {'X': {'a': {'one': 10,                       'two': 20},                  'b': {'one': 10,                       'two': 20}},            'Y': {'a': {'one': 10,                       'two': 20},                 'b': {'one': 10,                       'two': 20}}} 

The structure of the flat dictionary is such that there should not be any problems with ambiguities. I want it to work for dictionaries of arbitrary depth, but performance is not really an issue. I've seen lots of methods for flattening a nested dictionary, but basically none for nesting a flattened dictionary. The values stored in the dictionary are either scalars or strings, never iterables.

So far I have got something which can take the input

test_dict = {'X_a_one': '10',              'X_b_one': '10',              'X_c_one': '10'} 

to the output

test_out = {'X': {'a_one': '10',                    'b_one': '10',                    'c_one': '10'}} 

using the code

def nest_once(inp_dict):     out = {}     if isinstance(inp_dict, dict):         for key, val in inp_dict.items():             if '_' in key:                 head, tail = key.split('_', 1)                  if head not in out.keys():                     out[head] = {tail: val}                 else:                     out[head].update({tail: val})             else:                 out[key] = val     return out  test_out = nest_once(test_dict) 

But I'm having trouble working out how to make this into something which recursively creates all levels of the dictionary.

Any help would be appreciated!

(As for why I want to do this: I have a file whose structure is equivalent to a nested dict, and I want to store this file's contents in the attributes dictionary of a NetCDF file and retrieve it later. However NetCDF only allows you to put flat dictionaries as the attributes, so I want to unflatten the dictionary I previously stored in the NetCDF file.)


output = {}  for k, v in source.items():     # always start at the root.     current = output      # This is the part you're struggling with.     pieces = k.split('_')      # iterate from the beginning until the second to last place     for piece in pieces[:-1]:        if not piece in current:           # if a dict doesn't exist at an index, then create one           current[piece] = {}         # as you walk into the structure, update your current location        current = current[piece]      # The reason you're using the second to last is because the last place     # represents the place you're actually storing the item     current[pieces[-1]] = v 


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: