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}}}