如何在java中使用嵌套集模型将平面列表转换为嵌套树?
我正在使用在我的postgres数据库中存储类别层次结构。我能够查询给定类别ID的树,并查看其所有子级及其所在的深度。该查询的响应如下所示:如何在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
[
{
"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()));
}