首页 > 解决方案 > 如何访问嵌套 json 对象的父级

问题描述

我有一个任意嵌套的 JSON 对象(使用 json.load 解析),由字典、列表、原语等组成。我首先使用递归遍历它并以 linux fs 格式跟踪节点的路径(对于列表,我附加 /元素到路径,因此在特定路径可以有多个对象),如下:

def traverse(node, path =''):
   if isinstance(node, dict):
      for key in node:
         traverse(node[key], path+'/'+key)
   elif isinstance(node, list):
      for elem in node:
         traverse(elem,path+'/element')

每个节点可能包含一个字符串,该字符串需要使用可以存在于树中任何位置的对象的值来填充,在当前节点的相对路径中引用,例如:“{../../key} {./child1 /child2/key}”。
问题:我可以访问当前节点的子节点的值,但不能直接访问当前节点的父节点。
我认为的解决方案:我认为的一种解决方案是拥有一个元组列表(子,父)并将当前节点与我要递归的子节点一起存储,然后在我需要向上时反向搜索该列表。这有点危险,因为如果孩子是原始值,那么它将等于任何其他具有相同值和类型的孩子,因此我可能会检索到错误的父母,但我认为反向遍历列表应该注意对吗?
我认为一个不同的解决方案是有一个字典,其中键是孩子的路径并重视父节点。我认为这应该会更好,因为唯一的时间路径冲突是列表元素,但它们都有相同的父元素,所以我认为应该没问题。

还有其他建议吗?或者对这两种解决方案有何评论?谢谢

标签: pythonjsonparent-childparentchildren

解决方案


返回 dict 的父级(或任何没有反向指针的递归结构)的唯一方法是在遍历时记住它。

但请注意,您已经这样做了:您的path字符串是从顶部到当前节点的路径。

让我们编写一个使用路径的函数:

def follow(head, path):
    if not path:
        return head
    first, _, rest = path.partition('/')
    return follow(head[first], rest)

当然,将它们构建path为键元组而不是字符串可能会更好,因此我们不必将它们分开(因此我们不必担心如果任何键可能会转义或引用包含/等);你总是join可以在最后。

path并且将其构建为节点(或键节点对)的元组而不只是键可能会更好,因此我们可以在恒定时间内访问父节点path[-1]而不是在对数时间内访问父节点follow(head, path)。但这实际上取决于您实际上要做什么;您的真实代码可能不只是遍历树,建立到每个节点的路径,然后对它们什么都不做。


然而,解决这个问题的一个非常好的方法是将遍历从里到外:制作traverse一个迭代器:

def traverse(node, path =''):
   if isinstance(node, dict):
      for key in node:
         yield from traverse(node[key], path+'/'+key)
   elif isinstance(node, list):
      for elem in node:
         yield from traverse(elem,path+'/element')
   yield (node, path)

现在我们可以循环traverse执行任何我们想做的事,作为后序深度优先遍历:

for node, path in traverse(root):
    # do something

现在您可以轻松地将其更改为 yield node, parent, path(无论parent是父节点,还是父键,或者您想要的任何东西)。


推荐阅读