拥有以下json:
{
'a': {
'children': [],
'name': 'a'
},
'b': {
'children': [{
'x': {
'children': [],
'name': 'x'
}
}, {
'y': {
'children': [{
'z': {
'children': [],
'name': 'z'
}
}]
}]
}
}
最终结果应为:
a
b -> x
b -> y -> z
我无法解决我需要解决此问题的递归函数。链接列表是否为此解决方案?我的数据中存在未知级别的递归,因此该函数应该继续返回任何子节点。我没有问题递归地列出所有节点,但是,跟踪它们是我的问题。
def print_tree(tree, prev=None, child=False):
for node in tree:
print(node['name'])
if len(node['children']):
print_tree(node['children'])
print_tree(tree_data)
我在这里缺少什么逻辑来跟踪这个?
答案 0 :(得分:2)
您的代码存在很多问题
JSON无效,在最后}
之前错过了结束]
您的b
和y
个节点没有设置name
您的结构不一致:数据的每个项目都是一个节点,children
中的每个元素都是一个节点,但您的数据本身不是一个节点。此外,您的最外层数据使用{ 'a': ..., 'b': ... }
结构,但子项使用[ { 'a': ... }, { 'b': ... } ]
结构。
dict-wrapping节点使得很难将实际的节点输出。也就是说,如果我向您{ 'x': nodeX }
提供'x'
未知值,则您的程序很难提取nodeX
我们首先修复 1 和 2
data = \
{ 'a': { 'children': []
, 'name': 'a'
}
, 'b': { 'children': [ { 'x': { 'children': []
, 'name': 'x'
}
}
, { 'y': { 'children': [ { 'z': { 'children': []
, 'name': 'z'
}
}
]
, 'name': 'y' # you missed this
}
} # you missed this
]
, 'name': 'b' # you missed this
}
}
然后我们通过使用root
节点构建统一结构来修复 3
root = \
{ 'root': { 'children': [ {k:v} for (k,v) in data.items() ]
, 'name': 'root'
}
}
然后我们使用unwrap_node
帮助
def unwrap_node (wrapped_node):
node, *_ = wrapped_node.values()
if 'children' in node and len (node['children']) > 0:
return { 'name': node['name']
, 'children': [ unwrap_node(n) for n in node['children'] ]
}
else:
return node
现在我们了解你的问题。我们编写了一个通用的traverse
函数,它只为树中的每个节点生成一个祖先路径( list )
def traverse (node, path = []):
if 'children' in node and len (node['children']) > 0:
for n in node['children']:
yield from traverse (n, path + [ node ])
else:
yield path + [ node ]
使用每个祖先路径,我们可以通过name
属性轻松加入节点,并使用"->"
for path in traverse (unwrap_node (root)):
print (" -> ".join (node['name'] for node in path))
# root -> a
# root -> b -> x
# root -> b -> y -> z
最后,与上面的循环类似,实现所需的输出写入print_tree
。我们也可以过滤掉root -> ...
的打印
def print_tree (node):
for path in traverse (unwrap_node (node)):
print (" -> ".join (n['name'] for n in path if n['name'] is not 'root'))
print_tree (root)
# a
# b -> x
# b -> y -> z
如果您解决了JSON的严重结构问题,则可以避免必须处理解决方法
答案 1 :(得分:1)
如果我这样做,我会收集列表中的路径,然后构建字符串。这样做的好处是可以轻松地更改您想要对这些路径执行的操作(例如,更改输出格式,将它们传递给另一个函数等),而无需更改逻辑。
为此,我将创建一个帮助函数来处理构建路径并具有我计划调用的函数,只需收集/转换结果。如下所示:
# this function collects the paths as lists (e.g. ['b', 'y', 'z']) and returns a list of those paths
def get_paths(tree):
paths = []
for branch in tree:
name = tree[branch]['name']
children = tree[branch]['children']
if len(children):
# this mostly accounts for the fact that the children are a dictionary in a list
for node in children:
# get the paths from the children
sub_paths = get_paths(node)
# add this element to the beginning of those paths
for path in sub_paths:
path.insert(0, name)
# transfer modified sub-paths to list of paths
paths.extend(sub_paths)
else:
# leaf node, add as a path with one element
paths.append([name])
return paths
# this function uses the above function to get the paths and then prints the results as desired
def print_tree(tree):
paths = get_paths(tree)
print(paths)
# do whatever you want with the paths
for path in paths:
print(' -> '.join(path))
对于您的输入(修改为为' y'和' b'添加名称),提供:
a
b -> x
b -> y -> z