Even though this question was answered a long time ago I wanted to give another solution that, to me, seems quite a bit cleaner. I mostly use this with lists of parents and children that get zipped together. For example
parents = [None, 1, 2, 3, 3, 2, 6, 6, 1, 9, 10, 10, 9, 13, 13]
children = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
# {1: {2: {3: {4: {}, 5: {}}, 6: {7: {}, 8: {}}}, 9: {10: {11: {}, 12: {}}, 13: {14: {}, 15: {}}}}}
Implementation:
def create_tree(node_map, root=None):
""" Given a list of tuples (child, parent) return the nested dictionary representation.
"""
def traverse(parent, node_map, seen):
children = {}
for edge in node_map:
if edge[1] == parent and edge[0] not in seen:
seen.add(edge[0])
children[edge[0]] = traverse(edge[0], node_map, seen)
return children
return traverse(root, node_map, {root})
Usage:
Example of root the exclusion.
We want the root to be "a" but is excluded because a root should be indicated as having no parent (None
).
parents = ["a", "b", "c", "a", "b", "e", "e"]
children = ["b", "c", "d", "e", "f", "g", "h"]
edges = list(zip(children, parents))
test_tree = create_tree(edges, "a")
print(test_tree)
# result {'b': {'c': {'d': {}}, 'f': {}}, 'e': {'g': {}, 'h': {}}}
Adding the root with no parent designates the node as the root.
parents = [None, "a", "b", "c", "a", "b", "e", "e"]
children = ["a", "b", "c", "d", "e", "f", "g", "h"]
edges = list(zip(children, parents))
test_tree = create_tree(edges, None)
print(test_tree)
# result: {'a': {'b': {'c': {'d': {}}, 'f': {}}, 'e': {'g': {}, 'h': {}}}}
Multiple trees can be represented by having multiple roots.
parents = [None, "a", "b", "c", None, "b", "e", "e"]
children = ["a", "b", "c", "d", "e", "f", "g", "h"]
edges = list(zip(children, parents))
test_tree = create_tree(edges, None)
print(test_tree)
# result: {'a': {'b': {'c': {'d': {}}, 'f': {}}}, 'e': {'g': {}, 'h': {}}}
To get the desired output from the original post we find and designate the roots.
edges = [
#first value is child, second is parent
(0, 1),
(1, 3),
(8, 7),
(3, 6),
(4, 3),
(5, 3)
]
roots = {edge[1] for edge in edges} - {edge[0] for edge in edges}
edges += [(root, None) for root in roots]
test_tree = create_tree(edges, None)
print(test_tree)
# result: {6: {3: {1: {0: {}}, 4: {}, 5: {}}}, 7: {8: {}}}