python:从零散的字典组装成树状嵌套字典
最近工作接触到图数据库,图和树的存储形式是一对对基本的指向关系。
当需要访问时,不需要知道整体结构,只需要知道子节点,就可以把图结构表示出来了。
出于好奇,这里将这些基本的指向关系组成一个完整的结构。
首先,我们把问题简化,python中最基本的表示关系的数据结构是字典,
假设有这样一组关系,我们把它们用字典表示:
dict_list = [{
'a': "b"},
{
'a': "c"},
{
'a': "d"},
{
'b': "e"},
{
'a': "f"},
{
'd': "g"},
{
'd': "h"},
{
'e': "i"}]
组成树的过程分成三步:
1.找根节点
2.找出所有节点的子节点
3.深度优先遍历(或广度优先遍历)组装成最终的树
说明:不能用这种方式生成前缀树(Trie), 因为在前缀树中,相同字母是可以重复出现在不同位置的,而在这里一个字母只能出现在一个地方,在知识图谱中比较适用。
找根节点
我们先把根节点找出来,找根的依据是它没有在值中出现过,只能出现在键里:
# 首先,找根节点的方法
possible_root = set()
impossible_root = set()
for d in dict_list:
possible_root |= d.keys() # 根节点只能在键里
impossible_root |= set(d.values()) # 值一定不是根节点
# 既是键又不是值,只能是根,由于只有一个根,剩下的就只有一个根节点
root_set = possible_root - impossible_root
# 既是值又没有作为键出现过,说明没有节点在它之后,就是叶子节点
leaf_set = impossible_root - possible_root
看看结果:
print("root_set: ", root_set)
print("leaf_set: ", leaf_set)
成功找到根a:
找出所有节点的子节点
由于我们目标是组装成完整的树,因此要把各节点的所有子节点都找出来:
group = {
}
for d in dict_list:
for k, v in d.items():
group.setdefault(k, [])
group[k].append(v)
print(group)
结果:
深度优先遍历组装成最终的树
有了group这个信息,就可以把完整的嵌套字典拼出来了:
def dfs(temp, sub_tree):
for r in temp:
children = group.get(r)
if children is None:
return
sub_tree[r] = {
}
for child in children:
sub_tree[r][child] = {
}
dfs({
child}, sub_tree[r])
result = {
}
# 从root开始
dfs(root_set, sub_tree=result)
print(result)
结果:
完整代码
完整代码:
from pprint import pprint
dict_list = [{
'a': "b"},
{
'a': "c"},
{
'a': "d"},
{
'b': "e"},
{
'a': "f"},
{
'd': "g"},
{
'd': "h"},
{
'e': "i"}]
# 首先,找根节点的方法
possible_root = set()
impossible_root = set()
for d in dict_list:
possible_root |= d.keys() # 根节点只能在键里
impossible_root |= set(d.values()) # 值一定不是根节点
# 既是键又不是值,只能是根,由于只有一个根,剩下的就只有一个根节点
root_set = possible_root - impossible_root
# 既是值又没有作为键出现过,说明没有节点在它之后,就是叶子节点
leaf_set = impossible_root - possible_root
print("root_set: ", root_set)
print("leaf_set: ", leaf_set)
group = {
}
for d in dict_list:
for k, v in d.items():
group.setdefault(k, [])
group[k].append(v)
pprint(group)
def dfs(temp, sub_tree):
for r in temp:
children = group.get(r)
if children is None:
return
sub_tree[r] = {
}
for child in children:
sub_tree[r][child] = {
}
dfs({
child}, sub_tree[r])
result = {
}
# 从root开始
dfs(root_set, sub_tree=result)
pprint(result)