如何在java中使用嵌套集模型将平面列表转换为嵌套树?

如何在java中使用嵌套集模型将平面列表转换为嵌套树?,java,tree,java-stream,hierarchy,Java,Tree,Java Stream,Hierarchy,我正在使用在我的postgres数据库中存储类别层次结构。我能够查询给定类别ID的树,并查看其所有子级及其所在的深度。该查询的响应如下所示: [ { "id": "07e0b6c2-49cd-440b-a900-0f3d7ab88022", "categoryId": "80d15a99-9e42-4b72-b44b-0b222ca5173e", "n

我正在使用在我的postgres数据库中存储类别层次结构。我能够查询给定类别ID的树,并查看其所有子级及其所在的深度。该查询的响应如下所示:

[
    {
        "id": "07e0b6c2-49cd-440b-a900-0f3d7ab88022",
        "categoryId": "80d15a99-9e42-4b72-b44b-0b222ca5173e",
        "name": "Root",
        "lft": 1,
        "rgt": 18,
        "depth": 0
    },
    {
        "id": "ae53be00-c312-4cd5-a6b2-6baeaf760577",
        "categoryId": "9b8bca09-2447-494c-be0d-0b3af7d30671",
        "name": "Cat A",
        "lft": 2,
        "rgt": 9,
        "depth": 1
    },
    {
        "id": "0a5d4b90-29b9-4c50-a436-d129dc6983ea",
        "categoryId": "d06a143b-523e-4136-8a17-1049abbf76f4",
        "name": "Cat B",
        "lft": 3,
        "rgt": 4,
        "depth": 2
    },
    {
        "id": "11421455-abc0-464c-8bd0-e2d79302c270",
        "categoryId": "5af63d5b-f480-4620-8393-f4b93f7972e0",
        "name": "Cat D",
        "lft": 5,
        "rgt": 6,
        "depth": 2
    },
    {
        "id": "4463dbce-a2bf-42fe-a864-59309ba54d22",
        "categoryId": "21191930-a5b9-4868-883f-3798f29d70a3",
        "name": "Cat E",
        "lft": 7,
        "rgt": 8,
        "depth": 2
    },
    {
        "id": "0f40e7a0-e6eb-44a4-a9bd-b61512daa236",
        "categoryId": "34b127e8-7a8f-40b3-9b7e-63c8d507cc7b",
        "name": "Cat F",
        "lft": 10,
        "rgt": 11,
        "depth": 1
    },
    {
        "id": "87e9991e-085c-47a5-8357-79c0e467b8ec",
        "categoryId": "dfbbaac7-dda3-4f34-a787-183803f8e6fa",
        "name": "Cat G",
        "lft": 12,
        "rgt": 17,
        "depth": 1
    },
    {
        "id": "8a95b0ab-cf74-4083-9d17-40e70468350a",
        "categoryId": "f7f04485-d089-4a5d-98cd-20b0abeba8fc",
        "name": "Cat H",
        "lft": 13,
        "rgt": 14,
        "depth": 2
    },
    {
        "id": "dccee476-af73-4eb6-a595-f862984d4af6",
        "categoryId": "0eb165ec-0347-4336-8fc2-35c124bf26f2",
        "name": "Cat I",
        "lft": 15,
        "rgt": 16,
        "depth": 2
    }
]
你会注意到树已经被压扁了。我试图将上述结构放入一个嵌套的树结构中,我可以将其作为JSON返回到我的UI。理想情况下是这样的(为简洁起见省略数据):

我尝试了一系列选项,最近的一个选项是将原始列表流式传输到地图中,然后根据每个节点所在的深度收集其值。这并不能完全满足我的要求,因为它将处于同一级别但不一定属于同一棵树的节点分组

List<List<CategoryTree>> listOfLists = new ArrayList<>(
                categoryTreeList.stream()
                        .collect(Collectors.groupingBy(CategoryTree::getDepth))
                        .values());
List listofList=新的数组列表(
CategoryFileList.stream()
.collect(收集器.groupingBy(CategoryTree::getDepth))
.values());
似乎我应该尝试关闭
lft
rgt
值,以确定给定列表中的节点是否有任何子节点,这些子节点将由大于1的值表示


如何解决这个问题?

我建议您创建一个保存结构数据的类,而不是尝试使用原始映射

class Node {
    private final String id;
    private final String category;
    private Node left = null;
    private Node right = null;

    public Node(String id, String category) {
        this.id = id;
        this.category = category;
    }

    // left and right setters
}
您需要在两次过程中构建结构

第一步是创建节点并将其添加到列表中,以便可以使用它们的索引

List<Node> nodes = new ArrayList<>();
for (row: queryResult) {
    nodes.add(new Node(row.id(), row.category()));
}
有很多方法可以一次完成,然后解决转发引用,但我真的怀疑这是否值得

如果不能保证根节点是列表中的第一个节点,则需要在列表中查找不是任何其他节点的子节点的节点

实际上,没有必要存储或使用深度,除非您特别需要它用于其他用途。即使如此,最好还是派生它(通过维护一个
父字段并向上遍历层次结构),除非该结构保证是静态的


转换为json最好使用一个库,比如gson,然后是一个自定义的类转换器,它使用递归来转换整个结构。

运行此代码时,该结构不会被列表中的最后一个节点覆盖吗<代码>节点=节点.get(i++)?该命令只是与查询结果中的行并行地遍历列表中的节点。它不会改变结构。
List<Node> nodes = new ArrayList<>();
for (row: queryResult) {
    nodes.add(new Node(row.id(), row.category()));
}
int i = 0;
for (row: queryResult) {
    Node node = nodes.get(i++);
    if (row.lft())
        node.setLeft(nodes.get(row.lft()));
    if (row.rgt())
        node.setRight(nodes.get(row.rgt()));
}