2

我有一个我试图解析的 jsons 列表(最初是来自TestRail API getcases的响应)。这是一个示例 json:

[
{
    "id": 1,
    "parent_id": null,
},
{
    "id": 2,
    "parent_id": 1,
},
{
    "id": 6,
    "parent_id": null,
},
{
    "id": 16,
    "parent_id": 2,
},
{
    "id": 7,
    "parent_id": 1,
},
{
    "id": 3,
    "parent_id": 6
}
]

我想做的是弄清楚哪些 ID 属于原始父 ID。例如id:1,对于他们来说,它们"id": 6,是最顶层的父节点"parent_id": null

我想让所有子节点都属于最顶层的父节点。在此示例中,这是基于parent_id

1 -> [2,7] -> 16

6 -> 3

主要目标是确定顶级父节点的所有子(和子)节点是什么。我对了解子父/子关系不感兴趣。

我要解析的是得到以下输出:

{
 1: [2,7,16],
 6: 3
}

一种方法是使用几个嵌套的 for 循环,对于每个顶级父节点检查它是否呈现为parent_id并递归地使用它,但这看起来不是一个很好的方法。

将不胜感激任何意见/建议

4

1 回答 1

0
import json

from collections import defaultdict

data = json.loads(
    '[{"id": 1, "parent_id": null}, {"id": 2, "parent_id": 1}, {"id": 6, "parent_id": null}, {"id": 16, "parent_id": 2}, {"id": 7, "parent_id": 1}, {"id": 3, "parent_id": 6}]')

parents = {d['id']: d['parent_id'] for d in data}

class RootsDict(dict):
    def __missing__(self, key):
        parent = parents[key]
        if parent is None:
            return key
        else:
            return self[parent]

roots_dict = RootsDict()
descendants = defaultdict(list)

for d in data:
    id_ = d['id']
    if d['parent_id'] is not None:
        descendants[roots_dict[id_]].append(id_)

print(descendants)  # {1: [2, 16, 7], 6: [3]}

roots_dict is designed so that roots_dict[node] will return the top level parent of node, or node itself if it's already a root. __missing__ is a special method that can be overridden for dicts. It's called when key is requested from the dict but isn't present. Whatever the method returns will then be placed in the dict at that value. So for example roots_dict[16] when first accessed will be set to equal roots_dict[2], which in turn will ask for roots_dict[1], which is just 1. The rest is pretty straightforward.

于 2018-05-03T20:57:25.783 回答