Skip to content

Instantly share code, notes, and snippets.

@pdscopes pdscopes/expand_dict.py
Last active Jun 19, 2019

Embed
What would you like to do?
Function to expand a, partially, flattened dictionary out to a nested dictionary
def expand_dict(dct, delimiter: str = '.') -> dict:
"""
Expand a (partially) flattened dot-notation dictionary.
:param dct: Dictionary/list to be expanded
:param delimiter: String that delimits flattened keys
:return: Expanded dictionary/list
"""
if isinstance(dct, dict):
stale_keys = []
fresh_keys = {}
for key in dct:
if delimiter in key:
# Make note of the stale key
stale_keys.append(key)
# Detect the root and sub keys
root_key, sub_key = key.split(delimiter, 1)
next_key, rest_key = sub_key.split(delimiter, 1) if delimiter in sub_key else (sub_key, None)
# Set the default for root_key
if isinstance(dct.get(root_key), list) or (next_key and next_key.isdigit()):
fresh_keys.setdefault(root_key, dct.get(root_key, []))
else:
fresh_keys.setdefault(root_key, dct.get(root_key, {}))
# Add the value
if next_key and next_key.isdigit():
next_key = int(next_key or '0')
sub_val = {rest_key: dct[key]} if rest_key else dct[key]
if len(fresh_keys[root_key]) > next_key:
fresh_keys[root_key][next_key].update(sub_val)
else:
fresh_keys[root_key].insert(next_key, sub_val)
elif isinstance(fresh_keys[root_key], dict):
fresh_keys[root_key].update({sub_key: dct[key]})
elif isinstance(fresh_keys[root_key], list):
fresh_keys[root_key].append({sub_key: dct[key]})
expand_dict(fresh_keys, delimiter)
else:
expand_dict(dct[key], delimiter)
# Remove the flat keys
for key in stale_keys:
dct.pop(key)
# Insert the expanded keys
dct.update(fresh_keys)
elif isinstance(dct, list):
for elem in dct:
expand_dict(elem, delimiter)
return dct
## This will expand out (partially) flattened dictionaries
if __name__ == '__main__':
# Expand completely flattened dictionary
expand_dict({'one.two.three': 'four'})
## output: {'one': {'two': {'three': 'four'}}}
# Expand completely flattened dictionary with overlaps
expand_dict({'parent.one': 'val_one', 'parent.two.three': 'four'})
## output: {'parent': {'one': 'val_one', 'two': {'three': 'four'}}}
# Expand partially flattened dictionary with overlaps
expand_dict({'parent': {'one': 'val_one'}, 'parent.two.three': 'four'})
## output: {'parent': {'one': 'val_one', 'two': {'three': 'four'}}}
# Expand a list of flattened dictionries
expand_dict([{'one.two': 'three'}, {'four.five': 'six'}])
## output: [{'one': {'two': 'three'}}, {'four': {'five': 'six'}}]
# Expand a dictionary with integer keys
expand_dict({'alpha.0': 'one', 'alpha.1': 'two'})
## output: {'alpha': ['one', 'two']}
# Expand a dictionary with integer keys and overlap
expand_dict({'alpha.0.bar': 'one', 'alpha.0.baz': 'two', 'alpha.1.bar': 'three'})
## output: {'alpha': [{'bar': 'one', 'baz': 'two'}, {'bar': 'three'}]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.