给定一个字典,其中键是元组(值为数字或标量),如何用Python的方式将其转换为嵌套字典?问题在于,从输入到输入,元组的长度是任意的。
下面的代码示例中,d1、d2和d3表现出逐渐增加的嵌套性:
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)))
它们所产生的嵌套版本将是:
# 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: # ...
我的尝试:我喜欢在许多其他SO答案中提供的初始化空数据结构的技巧:
from collections import defaultdict
def nested_dict():
return defaultdict(nested_dict)
但是我在实施时遇到了困难,因为层级数不确定。我可以使用类似以下的内容:
def nest(d: dict) -> dict:
res = nested_dict()
for (i, j, k), v in d.items():
res[i][j][k] = v
return res
但是这只适用于d2
,因为其键名拥有3个级别(i、j、k)。
以下是我试图推广此解决方案的尝试,但我猜测还有更简单的方法。
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}}}
groupby()
是昂贵的,因为输入保证需要排序!排序会增加O(NlogN)的成本,当一个简单的O(N)循环就可以完成时,这是过度的。此外,把所有内容都放在一行上也非常昂贵。 - Martijn Pietersitertools.groupby
来说,有序输入是必要的。不过,我认为itertools.groupby
使递归逻辑变得更加容易,也许更加清晰。 - Ajax1234