概述
在实际开发中经常遇到需要查询树结构的需求。有两种方法,一种是递归查询子集,另一种是用Map映射子集。
递归
首先找到所有的一级主题,即没有父节点的类别。
然后通过stream.Map遍历处理每一个主题,
然后每一个一级主题都设置其子主题:
topicTree.setChildren(findChildren2(topicTree, topicTreeList))
findChildren2就是找到子主题的方法
@Override
public List<TopicTree> queryTopicTree2() {
List<TopicTree> topicTreeList = this.list(Wrappers.<TopicTree>lambdaQuery().orderByDesc(TopicTree::getOrders));
List<TopicTree> list = topicTreeList.stream()
.filter(topicTree -> Objects.isNull(topicTree.getPid()))
.map(topicTree -> {
topicTree.setChildren(findChildren2(topicTree, topicTreeList));
return topicTree;
})
.collect(Collectors.toList());
return list;
}
输入的参数有两个,一个是当前的主题opicTree,另一个是所有主题的列表。
找到子主题的关键在于,找到当前主题的id=子主题的pid。
过滤之后,用map处理每个子主题,而子主题的子主题则递归调用findChirdren2方法查找。
private List<TopicTree> findChildren2(TopicTree topicTree, List<TopicTree> topicTreeList) {
List<TopicTree> list = topicTreeList.stream()
.filter(t -> Objects.nonNull(t.getPid()) && Objects.equals(t.getPid(), topicTree.getId()))
.map(t -> {
t.setChildren(findChildren2(t, topicTreeList));
return t;
})
.collect(Collectors.toList());
if(CollectionUtils.isEmpty(list)){
return null;
}
return list;
}
Map
首先找到所有的主题列表。
然后用groupingBy方法分组。
这种方式的关键点在于理解groupingBy方法。
Optional.ofNullable(t.getPid()))表示:
如果t.getPid()为null,则返回一个Option.Empty():List的键值对。
如果t.getPid()不为null,则返回Pid:List的键值对。
所以接下来遍历map中每一个键值,而值又是一个list,所以再遍历list,找到当前主题的id,然后在map中找pid=id的键值对,该键值对的值就是子主题。
@Override
public List<TopicTree> queryTopicTree3() {
List<TopicTree> topicTreeList = this.list(Wrappers.<TopicTree>lambdaQuery().orderByDesc(TopicTree::getOrders));
Map<Optional<Long>, List<TopicTree>> topicTreeMap = topicTreeList.stream()
.collect(Collectors.groupingBy(t -> Optional.ofNullable(t.getPid())));
topicTreeMap.forEach((pid, topicTrees)->{
topicTrees.forEach(topicTree -> {
Long id = topicTree.getId();
if(Objects.isNull(id)){
return;
}
List<TopicTree> children = topicTreeMap.get(Optional.of(id));
if(!CollectionUtils.isEmpty(children)){
topicTree.setChildren(children);
}
});
});
List<TopicTree> res = topicTreeMap.get(Optional.empty());
if(!CollectionUtils.isEmpty(res)){
return res;
}
return res;
}