python – 从元组中任意嵌套的字典
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了python – 从元组中任意嵌套的字典,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3400字,纯文字阅读大概需要5分钟。
内容图文
![python – 从元组中任意嵌套的字典](/upload/InfoBanner/zyjiaocheng/696/a0d50789c9a249fabb4bcefcf428753b.jpg)
给定一个以元组为键(和数字/标量为值)的字典,什么是Pythonic转换为嵌套字典的方法?问题是从输入到输入,元组是任意长度的.
下面,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}}}
解决方法:
只需循环遍历每个键,并使用除键的最后一个元素之外的所有元素来添加词典.保持对如此设置的最后一个字典的引用,然后使用键元组中的最后一个元素在输出字典中实际设置键值对:
def nest(d: dict) -> dict:
result = {}
for key, value in d.items():
target = result
for k in key[:-1]: # traverse all keys but the last
target = target.setdefault(k, {})
target[key[-1]] = value
return result
您可以使用functools.reduce()来处理遍历字典的工作:
from functools import reduce
def nest(d: dict) -> dict:
result = {}
traverse = lambda r, k: r.setdefault(k, {})
for key, value in d.items():
reduce(traverse, key[:-1], result)[key[-1]] = value
return result
我使用了dict.setdefault()而不是auto-vivication defaultdict(nested_dict)选项,因为这会生成一个常规字典,当它们尚不存在时不会进一步隐式添加密钥.
演示:
>>> from pprint import pprint
>>> pprint(nest(d1))
{'A': {0: 0, 1: 1}, 'B': {0: 2, 1: 3}}
>>> pprint(nest(d2))
{'A': {0: {False: 1, True: 0}, 1: {False: 3, True: 2}},
'B': {0: {False: 5, True: 4}, 1: {False: 7, True: 6}}}
>>> pprint(nest(d3))
{'C': {0: {False: {'A': 2, 'B': 3}, True: {'A': 0, 'B': 1}},
1: {False: {'A': 6, 'B': 7}, True: {'A': 4, 'B': 5}}},
'D': {0: {False: {'A': 10, 'B': 11}, True: {'A': 8, 'B': 9}},
1: {False: {'A': 14, 'B': 15}, True: {'A': 12, 'B': 13}}}}
注意,上面的解决方案是一个干净的O(N)循环(N是输入字典的长度),而Ajax1234提出的groupby解决方案必须对输入进行排序才能工作,从而使其成为O(NlogN)解决方案.这意味着对于具有1000个元素的字典,groupby()将需要10.000步来产生输出,而O(N)线性循环仅需要1000步.对于一百万个键,这增加到2000万步等.
此外,Python中的递归速度很慢,因为Python无法将这些解决方案优化为迭代方法.函数调用相对昂贵,因此使用递归会带来显着的性能成本,因为您会大大增加函数调用的数量并扩展帧堆栈操作.
计时表明这有多重要;使用您的样品d3和100k运行,我们很容易看到5倍的速度差异:
>>> from timeit import timeit
>>> timeit('n(d)', 'from __main__ import create_nested_dict as n, d3; d=d3.items()', number=100_000)
8.210276518017054
>>> timeit('n(d)', 'from __main__ import nest as n, d3 as d', number=100_000)
1.6089267160277814
内容总结
以上是互联网集市为您收集整理的python – 从元组中任意嵌套的字典全部内容,希望文章能够帮你解决python – 从元组中任意嵌套的字典所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。