在Python中,当节点位于树的深度时,如何分配节点的子节点?

2024-09-30 20:24:24 发布

您现在位置:Python中文网/ 问答频道 /正文

我有描述树(父-子)的数据。我想在此基础上构建一个JSON文件,并将父级的子级分配给树中找到父级的任何位置。你知道吗

这个问题是这个答案的延伸: https://stackoverflow.com/a/57216064/1233240

代码:

file = [
     ('parent1', ['child1', 'child2', 'child3']),
     ('parent2', ['child4', 'child5', 'child6']),
     ('child1', ['child7', 'child8']),
     ('child5', ['child10', 'child33']),
     ('parent3', ['child1', 'child2', 'child3'])
]

json_dict = {}
flat_dict = {}

for parent, children in file:
    if parent in flat_dict:
        value = flat_dict[parent]
    else:
        value = {}
        flat_dict[parent] = json_dict[parent] = value
    for child in children:
        flat_dict[child] = value[child] = {}

电流输出:

{
    "parent1": {
        "child1": {
            "child7": {},
            "child8": {}
        },
        "child2": {},
        "child3": {}
    },
    "child1": {},
    "child2": {},
    "child3": {},
    "parent2": {
        "child4": {},
        "child5": {
            "child10": {},
            "child33": {}
        },
        "child6": {}
    },
    "child4": {},
    "child5": {
        "child10": {},
        "child33": {}
    },
    "child6": {},
    "child7": {},
    "child8": {},
    "child10": {},
    "child33": {},
    "parent3": {
        "child1": {},
        "child2": {},
        "child3": {}
    }
}

预期输出:

我希望所有child1节点如下:

"child1": {
    "child7": {},
    "child8": {}
}

但是我们可以看到,只有在parent1节点中它才保留它的子节点。你知道吗


Tags: valuedictparentflatchild1parent1child2child3
2条回答

一种方法是对链接的答案添加一个简单的修改,检查子对象是否已经存在,并使用现有的对象。你知道吗

json_dict = {}
flat_dict = {}

for parent, children in file:
    if parent in flat_dict:
        value = flat_dict[parent]
    else:
        value = {}
        flat_dict[parent] = json_dict[parent] = value
    for child in children:
        if child in flat_dict:
            value[child] = flat_dict[child]
        else:
            flat_dict[child] = value[child] = {}

在这两种情况下,都可以使用^{}来缩短代码,但我通常不会使用它,因为它会创建一个空的dictionary实例,即使这不是必需的:

json_dict = {}
flat_dict = {}

for parent, children in file:
    if parent in flat_dict:
        value = flat_dict[parent]
    else:
        value = json_dict[parent] = flat_dict[parent] = {}
    for child in children:
        value[child] = flat_dict.setdefault(child, {})

虽然第二个解决方案执行一些可能不必要的操作,但代码看起来确实更加清晰。你知道吗

同样干净但不必要对象较少的另一种方法是使用^{}

from collections import defaultdict

json_dict = {}
flat_dict = defaultdict(dict)

for parent, children in file:
    if parent in flat_dict:
        value = flat_dict[parent]
    else:
        value = json_dict[parent] = flat_dict[parent]
    for child in children:
        value[child] = flat_dict[child]

除了需要导入外,这个解决方案不会像基于dict的常规解决方案那样清晰地打印。但是,这不会以任何方式影响到到到JSON的转换。你知道吗

由于您注释说实际上不希望子节点位于根中,因此此处显示的代码段将仅将父节点放置在根中。但是,如果您稍后发现某个节点是子节点,则它们不会从根节点中删除该节点。这可以通过另一个简单的修改来实现,如defaultdict示例所示,但也适用于所有其他示例:

from collections import defaultdict

json_dict = {}
flat_dict = defaultdict(dict)

for parent, children in file:
    if parent in flat_dict:
        value = flat_dict[parent]
    else:
        value = json_dict[parent] = flat_dict[parent]
    for child in children:
        value[child] = flat_dict[child]
        json_dict.pop(child, None)

这里有一个IDEOne link和最后的答案。你知道吗

请记住,此代码不会检查循环引用。循环引用将自动从结果中删除自身。例如:

file = [
    ('A', ['B']),
    ('B', ['C']),
    ('C', ['A']),
]

希望这是你想要的。你知道吗

代码

relations = []
for k,l in file:
    for v in l:
        relations.append((k,v))
pop_list=[]
items = {}
for parent, child in relations:
    parent_dict = items.setdefault(parent, {})
    child_dict = items.setdefault(child, {})
    if child not in parent_dict:
        parent_dict[child] = child_dict
    pop_list.append(child)
for child in pop_list:
    if child in items.keys():
        items.pop(child)
print(items)

输出:

{'parent1': {'child1': {'child7': {}, 'child8': {}}, 'child2': {}, 'child3': {}}, 'parent2': {'child4': {}, 'child5': {'child10': {}, 'child33': {}}, 'child6': {}}, 'parent3': {'child1': {'child7': {}, 'child8': {}}, 'child2': {}, 'child3': {}}}

相关问题 更多 >