Reputation: 1141
It is not a strict nested list, it is a tree structure that looks like:
A = [a, [b, c,[d,e]]]
and the corresponding tree is :
a
/ \
b c
/ \
d e
Whenever there is a sublist after one element, the sublist corresponds to the child nodes of this element. Otherwise the elements are at the same layer. I want to generate a dictionary with each node as a key respectively, like:
child[a] = [b,c,d,e]
child[c] = [d,e]
How can I do that in python? Or is there other better suggestion on the tree structure conversion?
Upvotes: 0
Views: 795
Reputation: 20695
If you're going to be doing a lot of graph manipulation, I'd consider importing networkx
, as it will make things easier. To parse your nested list into a networkx
tree:
import networkx as nx
def parse_tree(node_list):
"""Parses a nested list into a networkx tree."""
tree = nx.DiGraph()
root = node_list[0]
tree.add_node(root)
queue = [(root, node_list[1])]
while queue:
parent, nodes = queue.pop(0)
prev = None
for node in nodes:
if isinstance(node, list):
queue.append((prev, node))
else:
tree.add_node(node)
tree.add_edge(parent, node)
prev = node
return tree
With this function, it's simple to get a dictionary of the descendants of each node:
>>> l = ["a", ["b", "c",["d","e"]]]
>>> tree = parse_tree(l)
>>> {node: nx.descendants(tree, node) for node in tree}
{'a': {'b', 'c', 'd', 'e'},
'b': set(),
'c': {'d', 'e'},
'd': set(),
'e': set()}
Upvotes: 2
Reputation: 31339
I still think you should use / get inspired by an existing implementation, but this may be what you're looking for if you need this to work:
#!/usr/bin/env python
# added a test case
B = ['a', ['b', 'c',['d','e']], 'f', ['g', 'h']]
A = ['a', ['b', 'c',['d','e']]]
# found on stack overflow - flatten list of kids for parent
def flatten(iterable):
"""Recursively iterate lists and tuples.
"""
for elm in iterable:
if isinstance(elm, (list, tuple)):
for relm in flatten(elm):
yield relm
else:
yield elm
# add data to an existing tree (recursive)
def treeify(tree, l):
if isinstance(l, list):
# avoid looking back
l.reverse()
for index in range(len(l)):
if isinstance(l[index], list):
parent_name = l[index+1]
# flatten kids to a list
tree[parent_name] = list(flatten(l[index]))
# continue in deeper lists
treeify(tree, l[index])
tree = {}
treeify(tree, A)
print tree
tree = {}
treeify(tree, B)
print tree
this reverses the list
to avoid looking back when traversing it. Tt sets the name as the next member if the current one is a list
, and traverses the child elements immediately (recursively).
Upvotes: 1