Given a dictionary with tuples as keys (and numbers/scalars as values), what is a Pythonic way to convert to a nested dictionary? The hitch is that from input-to-input, the tuples are of arbitrary length.
Below, d1
, d2
, and d3
demonstrate increasing nestedness:
from itertools import product
d1 = dict(zip(product('AB', [0, 1]), range(2*2)))
d2 = dict(zip(product('AB', [0, 1], [True, False]), range(2*2*2)))
d3 = dict(zip(product('CD', [0, 1], [True, False], 'AB'), range(2*2*2*2)))
And their resulting nested versions would be:
# For d1
{'A': {0: 0, 1: 1}, 'B': {0: 2, 1: 3}}
# For d2
{'A': {0: {True: 0, False: 1}, 1: {True: 2, False: 3}},
'B': {0: {True: 4, False: 5}, 1: {True: 6, False: 7}}}
# Beginning of result for d3
{
'C': {
0: {
True: {
'A': 0
'B': 1
},
False: {
'A': 2,
'B': 3
},
1: # ...
My attempts: I like the this trick for initializing an empty data structure, which is given in a number of other SO answers:
from collections import defaultdict
def nested_dict():
return defaultdict(nested_dict)
But am having trouble implementing this because the number of levels is uncertain. I could use something like:
def nest(d: dict) -> dict:
res = nested_dict()
for (i, j, k), v in d.items():
res[i][j][k] = v
return res
But this would only work for d2
because its keys have 3 levels (i, j, k) above.
Here's my attempt at a solution to generalizing this, but I'm guessing there is a simpler route.
def set_arbitrary_nest(keys, value):
"""
>>> keys = 1, 2, 3
>>> value = 5
result --> {1: {2: {3: 5}}}
"""
it = iter(keys)
last = next(it)
res = {last: {}}
lvl = res
while True:
try:
k = next(it)
lvl = lvl[last]
lvl[k] = {}
last = k
except StopIteration:
lvl[k] = value
return res
>>> set_arbitrary_nest([1, 2, 3], 5)
{1: {2: {3: 5}}}