Skip to content

Instantly share code, notes, and snippets.

@pmav99
Created November 28, 2021 12:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pmav99/e9402585bc7da65e061b09000600a540 to your computer and use it in GitHub Desktop.
Save pmav99/e9402585bc7da65e061b09000600a540 to your computer and use it in GitHub Desktop.
Convert a "dotted" dictionary to a nested one
from functools import reduce
from typing import Any
from typing import Dict
def merge(a, b, path=None):
""" Merge dictionary a into b (in-place)"""
# source: https://stackoverflow.com/a/7205107/592289
if path is None: path = []
for key in b:
if key in a:
if isinstance(a[key], dict) and isinstance(b[key], dict):
merge(a[key], b[key], path + [str(key)])
elif a[key] == b[key]:
pass # same leaf value
else:
raise Exception('Conflict at %s' % '.'.join(path + [str(key)]))
else:
a[key] = b[key]
return a
def dotted_to_nested(dotted_dict: Dict[str, Any]) -> Dict[Any, Any]:
"""
Convert a dictionary with "dotted" keys to a nested one.
>>> dotted_dict = {
"AAA.aaa.111": 1,
"AAA.aaa.222": 2,
"AAA.bbb.111": 3,
"AAA.bbb.333": 4,
"BBB.aaa": 5,
"CCC": 6,
"DDD.ddd.999": 7,
}
>>> dotted_to_nested(dotted_dict)
{'AAA': {'aaa': {'111': 1, '222': 2}},
'BBB': {'aaa': 5},
'CCC': 6,
'DDD': {'ddd': {'999': 7}}}
"""
# adapted from: https://stackoverflow.com/a/40401961/592289
list_of_dicts = []
for key, value in dotted_dict.items():
row_dict = {}
for i, subkey in enumerate(reversed(key.split("."))):
if i == 0:
row_dict = {subkey: value}
else:
row_dict = {subkey: row_dict}
list_of_dicts.append(row_dict)
nested_dict = reduce(merge, ({}, *list_of_dicts))
return nested_dict
# example
dotted_dict = {
"AAA.aaa.111": 1,
"AAA.aaa.222": 2,
"AAA.bbb.111": 3,
"AAA.bbb.333": 4,
"BBB.aaa": 5,
"CCC": 6,
"DDD.ddd.999": 7,
}
nested_dict = dotted_to_nested(dotted_dict)
from pprint import pprint
pprint(nested_dict)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment