O.r*_*rka 3 python dictionary iterable function generator
我发现自己制作多级词典相当多。我总是不得不编写非常冗长的代码来遍历包含大量临时变量的字典的所有级别。
有没有办法概括这个函数来迭代多个级别而不是硬编码并手动指定有多少级别?
def iterate_multilevel_dictionary(d, number_of_levels):
# How to auto-detect number of levels?
# number_of_levels = 0
if number_of_levels == 1:
for k1, v1 in d.items():
yield k1, v1
if number_of_levels == 2:
for k1, v1 in d.items():
for k2, v2 in v1.items():
yield k1, k2, v2
if number_of_levels == 3:
for k1, v1 in d.items():
for k2, v2 in v1.items():
for k3, v3 in v2.items():
yield k1, k2, k3, v3
# Level 1
d_level1 = {"a":1,"b":2,"c":3}
for items in iterate_multilevel_dictionary(d_level1, number_of_levels=1):
print(items)
# ('a', 1)
# ('b', 2)
# ('c', 3)
# Level 2
d_level2 = {"group_1":{"a":1}, "group_2":{"b":2,"c":3}}
for items in iterate_multilevel_dictionary(d_level2, number_of_levels=2):
print(items)
#('group_1', 'a', 1)
#('group_2', 'b', 2)
#('group_2', 'c', 3)
# Level 3
d_level3 = {"collection_1":d_level2}
for items in iterate_multilevel_dictionary(d_level3, number_of_levels=3):
print(items)
# ('collection_1', 'group_1', 'a', 1)
# ('collection_1', 'group_2', 'b', 2)
# ('collection_1', 'group_2', 'c', 3)
Run Code Online (Sandbox Code Playgroud)
我是在看到@VoNWooDSoN 的回答后写的。我把它变成了一个迭代器,而不是在函数内部打印,并进行了一些更改以使其更具可读性。所以在这里看到他的原始答案。
def flatten(d, base=()):
for k, v in d.items():
if isinstance(v, dict):
yield from flatten(v, base + (k,))
else:
yield base + (k, v)
Run Code Online (Sandbox Code Playgroud)
1-产量而不是印刷。
2-isinstance()而不是type这样的子类dict也可以工作。您也可以使用MutableMappingfromtyping模块而不是dict使其更通用。
3- IMO,(k, v)从中获取对比and.items()更具可读性。kd[k]
您是否想将其扩展为更通用的CAN(不必,如 OP 中的解决方案)接受数字depths以防万一?
考虑以下示例:
d_level1 = {"a": 1, "b": 2, "c": 3}
d_level2 = {"group_1": {"a": 1}, "group_2": {"b": 2, "c": 3}}
d_level3 = {"collection_1": d_level2}
for items in flatten(d_level3):
print(items)
print('------------------------------')
for items in flatten(d_level3, depth=0):
print(items)
print('------------------------------')
for items in flatten(d_level3, depth=1):
print(items)
print('------------------------------')
for items in flatten(d_level3, depth=2):
print(items)
Run Code Online (Sandbox Code Playgroud)
输出:
('collection_1', 'group_1', 'a', 1)
('collection_1', 'group_2', 'b', 2)
('collection_1', 'group_2', 'c', 3)
------------------------------
('collection_1', {'group_1': {'a': 1}, 'group_2': {'b': 2, 'c': 3}})
------------------------------
('collection_1', 'group_1', {'a': 1})
('collection_1', 'group_2', {'b': 2, 'c': 3})
------------------------------
('collection_1', 'group_1', 'a', 1)
('collection_1', 'group_2', 'b', 2)
('collection_1', 'group_2', 'c', 3)
Run Code Online (Sandbox Code Playgroud)
depth=None不考虑深度(仍然像你想要的那样工作)。但是现在通过从0到指定深度,2您可以看到我们能够迭代我们想要的深度。这是代码:
def flatten(d, base=(), depth=None):
for k, v in d.items():
if not isinstance(v, dict):
yield base + (k, v)
else:
if depth is None:
yield from flatten(v, base + (k,))
else:
if depth == 0:
yield base + (k, v)
else:
yield from flatten(v, base + (k,), depth - 1)
Run Code Online (Sandbox Code Playgroud)