Python - 从元组列表中生成字典(树)

Pyt*_*ast 9 python tree

我有以下列表: -

a = [(1, 1), (2, 1), (3, 1), (4, 3), (5, 3), (6, 3), (7, 7), (8, 7), (9, 7)]
Run Code Online (Sandbox Code Playgroud)

这是一个元组列表.元组内的元素的格式是(Id, ParentId)其根节点Id == ParentId.列表可以是元组的任何顺序.

我想使用上面的元组列表生成以下字典,

output = [{
    'id': 1,
    'children': [{
        {
            'id': 3,
            'children': [{
                {
                    'id': 5
                },
                {
                    'id': 4
                },
                {
                    'id': 6
                }
            }]
        },
        {
            'id': 2
        }
    }]
}, {
    'id': 7,
    'children': [{
        {
            'id': 9
        },
        {
            'id': 8
        }
    }]
}]
Run Code Online (Sandbox Code Playgroud)

即(就图表而言 - 阿甘)

    1            7
   / \          / \
  2   3        8  9
     /|\
    4 5 6
Run Code Online (Sandbox Code Playgroud)

我的最终输出应该是上面给出的字典.

我尝试了以下方法: -

我尝试过的解决方案如下: -

# set the value of nested dictionary.
def set_nested(d, path, value):
    reduce(lambda d, k: d.setdefault(k, {}), path[:-1], d)[path[-1]] = value
    return d

# returns the path of any node in list format
def return_parent(list, child):
    for tuple in list:
        id, parent_id = tuple
        if parent_id == id == child:
            return [parent_id]
        elif id == child:
            return [child] + return_parent(list, parent_id)

paths = []
temp = {}
for i in a:
    id, parent_id = i
    temp[id] = {'id': id}
    path = return_parent(a, id)[::-1]
    paths.append(path) # List of path is created

d = {}
for path in paths:
    for n, id in enumerate(path):
        set_nested(d, path[:n + 1], temp[id]) # setting the value of nested dictionary.

print d
Run Code Online (Sandbox Code Playgroud)

我得到的输出是

{
    '1': {
        '3': {
            '6': {
                'id': '6'
            },
            '5': {
                'id': '5'
            },
            'id': '3',
            '4': {
                '10': {
                    'id': '10'
                },
                'id': '4'
            }
        },
        '2': {
            'id': '2'
        },
        'id': '1'
    },
    '7': {
        '9': {
            'id': '9'
        },
        '8': {
            'id': '8'
        },
        'id': '7'
    }
}
Run Code Online (Sandbox Code Playgroud)

我接近它,但无法得到确切的输出.此外,还有更好的解决方案吗?

Dir*_*ann 13

这是一种更简单的方法.(编辑我从托马斯回答可以按任何顺序给出节点):Pass 1创建节点(即将它们添加到节点字典中),而Pass 2则创建父< - > children结构.

做出以下假设:没有周期(不清楚在这种情况下预期的输出是什么,Garret R指出),没有缺失的边缘,没有遗漏的树根.

a = [(1, 1), (2, 1), (3, 1), (4, 3), (5, 3), (6, 3), (7, 7), (8, 7), (9, 7)]

# pass 1: create nodes dictionary
nodes = {}
for i in a:
    id, parent_id = i
    nodes[id] = { 'id': id }

# pass 2: create trees and parent-child relations
forest = []
for i in a:
    id, parent_id = i
    node = nodes[id]

    # either make the node a new tree or link it to its parent
    if id == parent_id:
        # start a new tree in the forest
        forest.append(node)
    else:
        # add new_node as child to parent
        parent = nodes[parent_id]
        if not 'children' in parent:
            # ensure parent has a 'children' field
            parent['children'] = []
        children = parent['children']
        children.append(node)

print forest
Run Code Online (Sandbox Code Playgroud)

编辑:为什么你的解决方案不能按预期工作?

以下是关于顶级的提示:您要获取的输出是树列表.但是,您正在处理的变量(d)需要是字典,因为在函数set_nested中,您将setdefaults方法应用于它.