Python: 合并嵌套字典的列表并得到一个字典(树)
Python: Merge list of nested dictionary and get a dictionary (tree)
例如,我有以下“dict”列表:
List1= [{'Europe': {'DE': {'Berlin': ['jack']}}},
{'Europe': {'DE': {'KL': ['Paul']}}},
{'Europe': {'FR': {'Paris': ['Jean', "Pierre"]}}}]
我想用 Python 将其转换为具有树结构的字典,如:
output = {"Europe": { "DE": { "KL": ["Paul"],
"Berlin": ["Jack"]
},
"FR" : { "Paris": ["Jean", "Pierre"]}
}
}
你能帮帮我吗?我的函数获取 list1 和 return 输出字典 ?
谢谢
这可行,尽管我觉得可能有更优雅的方法。
all_country_codes = set([list(x['Europe'].keys())[0] for x in List1])
output = []
for code in all_country_codes:
results = [x['Europe'][code] for x in List1 if code in x['Europe'].keys()]
country_code_dict = {}
for country_dictionary in results:
country_code_dict.update(country_dictionary)
output.append({code: country_code_dict})
almost_there_dict = {}
for reformatted_dict in output:
almost_there_dict.update(reformatted_dict)
final_dict = {}
final_dict['Europe'] = almost_there_dict
这是一个简单的递归解决方案。此解决方案足够通用,能够支持字典结构中的任何未来更改,您甚至可以将其用于此国家/地区列表以外的目的。通过利用 dict
和 list
的可变性 属性,我们可以在每个递归调用中传递它并执行:
- 如果
lhs
(左边,这里是List1
)中的元素还没有出现在rhs
(右边,这里是result
), 按原样复制。
- 如果
lhs
中的元素已经出现在rhs
中,则递归调用合并内部元素。
- 如果
lhs
中的值是一个列表,将其添加到 rhs
。
import copy
import json
List1= [
{'Europe': {'DE': {'Berlin': ['Jack']}}},
{'Europe': {'DE': {'KL': ['Paul']}}},
{'Asia': {'PH': {'Manila': ['Jose', 'Rizal']}}},
{'Europe': {'FR': {'Paris': ['Jean', "Pierre"]}}},
{'Asia': {'PH': {'Manila': ['Andres']}}},
{'Asia': {'KH': {'Siem Reap': ['Angkor']}}},
{'Europe': {'DE': {'Berlin': ['Jill']}}},
{'Asia': {'PH': {'Cebu': ['Lapulapu']}}},
{'Asia': {'PH': {'Manila': ['Bonifacio']}}},
{'Europe': {'ES': {'Valencia': ['Paella']}}},
{'Asia': {'KH': {'Phnom Penh': ['Wat']}}},
{'Europe': {'ES': {'Valencia': ['Me gusta mucho!']}}},
{'Asia': {'PH': {'Palawan': ['Beach']}}},
{'Asia': {'PH': {'Palawan': ['Cave']}}},
{'Asia': {'PH': {'Palawan': []}}},
]
result = {}
def merge(lhs, rhs):
if isinstance(lhs, dict):
for key, value in lhs.items():
if key not in rhs:
rhs[key] = copy.deepcopy(value) # Thanks to @sabik for the code review (see comments section). To avoid updating the source data List1, here we would perform a deep copy instead of just <rhs[key] = value>.
else:
merge(value, rhs[key])
elif isinstance(lhs, list):
rhs.extend(lhs)
for item in List1:
merge(item, result)
print(json.dumps(result, indent=4))
输出:
{
"Europe": {
"DE": {
"Berlin": [
"Jack",
"Jill"
],
"KL": [
"Paul"
]
},
"FR": {
"Paris": [
"Jean",
"Pierre"
]
},
"ES": {
"Valencia": [
"Paella",
"Me gusta mucho!"
]
}
},
"Asia": {
"PH": {
"Manila": [
"Jose",
"Rizal",
"Andres",
"Bonifacio"
],
"Cebu": [
"Lapulapu"
],
"Palawan": [
"Beach",
"Cave"
]
},
"KH": {
"Siem Reap": [
"Angkor"
],
"Phnom Penh": [
"Wat"
]
}
}
}
我认为你可以使用嵌套的 defaultdict 来完成它。这是解决方案,它的灵感来自 Nested defaultdict of defaultdict
import json
from collections import defaultdict
# List1 = [{'Europe': {'DE': {'Berlin': ['jack']}}},
# {'Europe': {'DE': {'KL': ['Paul']}}},
# {'Europe': {'FR': {'Paris': ['Jean', "Pierre"]}}}]
List1 = [{'Europe': {'DE': {'Berlin': {'a': ['jack']}}}},
{'Europe': {'DE': {'Berlin': {'b': {'b1': ['xxx']}}}}},
{'Europe': {'FR': {'Paris': ['Jean', "Pierre"]}}}]
def create_tree():
return defaultdict(create_tree)
def set_node(i, node, k):
if isinstance(i, dict):
for k, v in i.items():
if isinstance(v, list):
node[k] = v
else:
node = node[k]
set_node(v, node, k)
def get_tree():
tree = create_tree()
for d in List1:
set_node(d, tree, None)
return tree
tree = get_tree()
# if you want to get the dict of tree, use:json.loads(json.dumps(tree))
print(json.dumps(tree, indent=4))
如果嵌套的深度 dict
没有改变,您可以尝试循环并在找到键时使用 setdefault
和 update
:-
List1= [{'Europe': {'DE': {'Berlin': ['Jack']}}},
{'Europe': {'DE': {'KL': ['Paul']}}},
{'Europe': {'FR': {'Paris': ['Jean', "Pierre"]}}}]
output = {}
for l in List1:
for k,v in l.items():
#outer key
output.setdefault(k, {})
for key,val in v.items():
#inner key
output[k].setdefault(key, {})
#update inner key
output[k][key].update(val)
哪个 returns(请记住,根据您的 Python 版本,dict
可能排序或不排序):
{'Europe': {'DE': {'Berlin': ['Jack'], 'KL': ['Paul']},
'FR': {'Paris': ['Jean', 'Pierre']}}}
例如,我有以下“dict”列表:
List1= [{'Europe': {'DE': {'Berlin': ['jack']}}},
{'Europe': {'DE': {'KL': ['Paul']}}},
{'Europe': {'FR': {'Paris': ['Jean', "Pierre"]}}}]
我想用 Python 将其转换为具有树结构的字典,如:
output = {"Europe": { "DE": { "KL": ["Paul"],
"Berlin": ["Jack"]
},
"FR" : { "Paris": ["Jean", "Pierre"]}
}
}
你能帮帮我吗?我的函数获取 list1 和 return 输出字典 ?
谢谢
这可行,尽管我觉得可能有更优雅的方法。
all_country_codes = set([list(x['Europe'].keys())[0] for x in List1])
output = []
for code in all_country_codes:
results = [x['Europe'][code] for x in List1 if code in x['Europe'].keys()]
country_code_dict = {}
for country_dictionary in results:
country_code_dict.update(country_dictionary)
output.append({code: country_code_dict})
almost_there_dict = {}
for reformatted_dict in output:
almost_there_dict.update(reformatted_dict)
final_dict = {}
final_dict['Europe'] = almost_there_dict
这是一个简单的递归解决方案。此解决方案足够通用,能够支持字典结构中的任何未来更改,您甚至可以将其用于此国家/地区列表以外的目的。通过利用 dict
和 list
的可变性 属性,我们可以在每个递归调用中传递它并执行:
- 如果
lhs
(左边,这里是List1
)中的元素还没有出现在rhs
(右边,这里是result
), 按原样复制。 - 如果
lhs
中的元素已经出现在rhs
中,则递归调用合并内部元素。 - 如果
lhs
中的值是一个列表,将其添加到rhs
。
import copy
import json
List1= [
{'Europe': {'DE': {'Berlin': ['Jack']}}},
{'Europe': {'DE': {'KL': ['Paul']}}},
{'Asia': {'PH': {'Manila': ['Jose', 'Rizal']}}},
{'Europe': {'FR': {'Paris': ['Jean', "Pierre"]}}},
{'Asia': {'PH': {'Manila': ['Andres']}}},
{'Asia': {'KH': {'Siem Reap': ['Angkor']}}},
{'Europe': {'DE': {'Berlin': ['Jill']}}},
{'Asia': {'PH': {'Cebu': ['Lapulapu']}}},
{'Asia': {'PH': {'Manila': ['Bonifacio']}}},
{'Europe': {'ES': {'Valencia': ['Paella']}}},
{'Asia': {'KH': {'Phnom Penh': ['Wat']}}},
{'Europe': {'ES': {'Valencia': ['Me gusta mucho!']}}},
{'Asia': {'PH': {'Palawan': ['Beach']}}},
{'Asia': {'PH': {'Palawan': ['Cave']}}},
{'Asia': {'PH': {'Palawan': []}}},
]
result = {}
def merge(lhs, rhs):
if isinstance(lhs, dict):
for key, value in lhs.items():
if key not in rhs:
rhs[key] = copy.deepcopy(value) # Thanks to @sabik for the code review (see comments section). To avoid updating the source data List1, here we would perform a deep copy instead of just <rhs[key] = value>.
else:
merge(value, rhs[key])
elif isinstance(lhs, list):
rhs.extend(lhs)
for item in List1:
merge(item, result)
print(json.dumps(result, indent=4))
输出:
{
"Europe": {
"DE": {
"Berlin": [
"Jack",
"Jill"
],
"KL": [
"Paul"
]
},
"FR": {
"Paris": [
"Jean",
"Pierre"
]
},
"ES": {
"Valencia": [
"Paella",
"Me gusta mucho!"
]
}
},
"Asia": {
"PH": {
"Manila": [
"Jose",
"Rizal",
"Andres",
"Bonifacio"
],
"Cebu": [
"Lapulapu"
],
"Palawan": [
"Beach",
"Cave"
]
},
"KH": {
"Siem Reap": [
"Angkor"
],
"Phnom Penh": [
"Wat"
]
}
}
}
我认为你可以使用嵌套的 defaultdict 来完成它。这是解决方案,它的灵感来自 Nested defaultdict of defaultdict
import json
from collections import defaultdict
# List1 = [{'Europe': {'DE': {'Berlin': ['jack']}}},
# {'Europe': {'DE': {'KL': ['Paul']}}},
# {'Europe': {'FR': {'Paris': ['Jean', "Pierre"]}}}]
List1 = [{'Europe': {'DE': {'Berlin': {'a': ['jack']}}}},
{'Europe': {'DE': {'Berlin': {'b': {'b1': ['xxx']}}}}},
{'Europe': {'FR': {'Paris': ['Jean', "Pierre"]}}}]
def create_tree():
return defaultdict(create_tree)
def set_node(i, node, k):
if isinstance(i, dict):
for k, v in i.items():
if isinstance(v, list):
node[k] = v
else:
node = node[k]
set_node(v, node, k)
def get_tree():
tree = create_tree()
for d in List1:
set_node(d, tree, None)
return tree
tree = get_tree()
# if you want to get the dict of tree, use:json.loads(json.dumps(tree))
print(json.dumps(tree, indent=4))
如果嵌套的深度 dict
没有改变,您可以尝试循环并在找到键时使用 setdefault
和 update
:-
List1= [{'Europe': {'DE': {'Berlin': ['Jack']}}},
{'Europe': {'DE': {'KL': ['Paul']}}},
{'Europe': {'FR': {'Paris': ['Jean', "Pierre"]}}}]
output = {}
for l in List1:
for k,v in l.items():
#outer key
output.setdefault(k, {})
for key,val in v.items():
#inner key
output[k].setdefault(key, {})
#update inner key
output[k][key].update(val)
哪个 returns(请记住,根据您的 Python 版本,dict
可能排序或不排序):
{'Europe': {'DE': {'Berlin': ['Jack'], 'KL': ['Paul']},
'FR': {'Paris': ['Jean', 'Pierre']}}}