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.)
Advertisement
Answer
Here is my take:
def nest_dict(flat): result = {} for k, v in flat.items(): _nest_dict_rec(k, v, result) return result def _nest_dict_rec(k, v, out): k, *rest = k.split('_', 1) if rest: _nest_dict_rec(rest[0], v, out.setdefault(k, {})) else: out[k] = v 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} nested = {'X': {'a': {'one': 10, 'two': 20}, 'b': {'one': 10, 'two': 20}}, 'Y': {'a': {'one': 10, 'two': 20}, 'b': {'one': 10, 'two': 20}}} print(nest_dict(flat) == nested) # True