一、树结构的三种组装方式(递归.双层for循环,map)

(1)递归

普通递归方法

 public Result getBmsMenuList(UserSessionVO userSessionInfo) {
// 查询顶级节点菜单
List<BmsMenuVO> bmsMenuVOList = bmsMenuDao.selectBmsMenuList(new BmsMenuQueryConditionVO()); for (BmsMenuVO bmsMenuVO : bmsMenuVOList) {
getBmsMenuListByRecursion(bmsMenuVO);
} return Result.createWithModels(null, bmsMenuVOList);
} private void getBmsMenuListByRecursion(BmsMenuVO bmsMenuVO) {
List<BmsMenuVO> bmsMenuVOS = bmsMenuDao.selectBmsMenuList(new BmsMenuQueryConditionVO().setParentId(bmsMenuVO.getId()));
if (CollectionUtils.isEmpty(bmsMenuVOS)) {
return;
}
bmsMenuVO.setChildBmsMenuList(bmsMenuVOS);
for (BmsMenuVO menuVO : bmsMenuVOS) {
getBmsMenuListByRecursion(menuVO);
}
}

stream流递归方法

//获取父节点
List<TreeSelect> collect = trees.stream().filter(m -> m.getParentId() == 0).map(
(m) -> {
m.setChildren(getChildrenList(m, trees));
return m;
}
).collect(Collectors.toList()); /**
* 获取子节点列表
* @param tree
* @param list
* @return
*/
public static List<TreeSelect> getChildrenList(TreeSelect tree, List<TreeSelect> list){
List<TreeSelect> children = list.stream().filter(item -> Objects.equals(item.getParentId(), tree.getId())).map(
(item) -> {
item.setChildren(getChildrenList(item, list));
return item;
}
).collect(Collectors.toList());
return children;
}

(2)双层for循环

// 查询主节点
List<BmsMenuVO> bmsMenuVOList = bmsRoleMenuDao.getAllRoleMenuList(condition); // 拼装结果
List<BmsMenuVO> bmsMenuTree = new ArrayList<>();
for (BmsMenuVO bmsMenuVO : bmsMenuVOList) {
// 根节点的父Id为null
if (bmsMenuVO.getParentId() == null) {
bmsMenuTree.add(bmsMenuVO);
}
for (BmsMenuVO menuVO : bmsMenuVOList) {
if (menuVO.getParentId() != null && menuVO.getParentId().equals(bmsMenuVO.getId())) {
if (CollectionUtils.isEmpty(bmsMenuVO.getChildBmsMenuList())) {
bmsMenuVO.setChildBmsMenuList(new ArrayList<>());
}
bmsMenuVO.getChildBmsMenuList().add(menuVO);
}
}
} // 返回结果
return Result.createWithModels(null, bmsMenuTree);

(3)map遍历

 // 查询所有节点
List<BmsMenuVO> bmsMenuVOList = bmsRoleMenuDao.getAllRoleMenuList(condition); // 拼装结果
List<BmsMenuVO> bmsMenuTree = new ArrayList<>();
// 用来存储节点的子元素map
Map<Long, BmsMenuVO> childBmsMenuMap = new LinkedHashMap<>();
for (BmsMenuVO menuVO : bmsMenuVOList) {
childBmsMenuMap.put(menuVO.getId(), menuVO);
}
for (Long bmsMenuId : childBmsMenuMap.keySet()) {
BmsMenuVO menuVO = childBmsMenuMap.get(bmsMenuId);
Long parentId = menuVO.getParentId();
if (parentId == null) {
bmsMenuTree.add(menuVO);
} else {
BmsMenuVO parentMenuVO = childBmsMenuMap.get(parentId);
if (parentMenuVO.getChildBmsMenuList() == null) {
parentMenuVO.setChildBmsMenuList(new ArrayList<>());
}
parentMenuVO.getChildBmsMenuList().add(menuVO);
}
}

2、使用递归查询某个节点所在的树结构

使用场景:当我们得到一个树形结构数据时,可能需要在树形结构上对数据进行筛选,例如通过文件夹(文件)名称模糊查询相关的文件夹并展现其父级。

缺点:需要查询出完整的树形结构才能用作筛选,在数据量非常庞大的时候并不适用。

@Data
public class TreeDto { private String id;
private String name;
private List<TreeDto> subsetTreeDtoList; public TreeDto(String id,String name,List<TreeDto> subsetTreeDtoList){
this.id = id;
this.name = name;
this.subsetTreeDtoList = subsetTreeDtoList;
}
}

筛选

  /**
* 树形筛选查找
* @param treeDtoList 树形集合
* @param idList 筛选条件(可以是其他条件)
* @return 包含的节点数据
*/
public static List<TreeDto> screenTree(List<TreeDto> treeDtoList, List<String> idList){
//最后返回的筛选完成的集合
List<TreeDto> screeningOfCompleteList = new ArrayList<>();
if (listIsNotEmpty(treeDtoList) && listIsNotEmpty(idList)){
for (TreeDto treeDto : treeDtoList){
List<TreeDto> subsetList = treeDto.getSubsetTreeDtoList();
//递归筛选完成后的返回的需要添加的数据
TreeDto addTreeDto = getSubsetPmsPlanPo(treeDto,subsetList,idList);
if (isNotEmpty(addTreeDto)){
screeningOfCompleteList.add(addTreeDto);
}
}
return screeningOfCompleteList;
}
return null;
} /**
* 筛选符合的集合并返回
* @param treeDto 树形类
* @param subsetTreeDtoList 子集集合
* @param idList 筛选条件
* @return 筛选成功的类
*/
public static TreeDto getSubsetPmsPlanPo(TreeDto treeDto,List<TreeDto> subsetTreeDtoList,List<String> idList){
//作为筛选条件的判断值
String id = treeDto.getId();
//有子集时继续向下寻找
if (listIsNotEmpty(subsetTreeDtoList)){
List<TreeDto> addTreeDtoList = new ArrayList<>();
for (TreeDto subsetTreeDto : subsetTreeDtoList){
List<TreeDto> subsetList = subsetTreeDto.getSubsetTreeDtoList();
TreeDto newTreeDto = getSubsetPmsPlanPo(subsetTreeDto,subsetList,idList);
//当子集筛选完不为空时添加
if (isNotEmpty(newTreeDto)){
addTreeDtoList.add(newTreeDto);
}
}
//子集满足条件筛选时集合不为空时,替换对象集合内容并返回当前对象
if (listIsNotEmpty(addTreeDtoList)){
treeDto.setSubsetTreeDtoList(addTreeDtoList);
return treeDto;
//当前对象子集对象不满足条件时,判断当前对象自己是否满足筛选条件,满足设置子集集合为空,并返回当前对象
}else if (listIsEmpty(addTreeDtoList) && idList.contains(id)){
treeDto.setSubsetTreeDtoList(null);
return treeDto;
}else {
//未满足筛选条件直接返回null
return null;
}
}else {
//无子集时判断当前对象是否满足筛选条件
if (idList.contains(id)){
return treeDto;
}else {
return null;
}
}
} /**
* 判断集合为空
* @param list 需要判断的集合
* @return 集合为空时返回 true
*/
public static boolean listIsEmpty(Collection list){
return (null == list || list.size() == 0);
} /**
* 判断集合非空
* @param list 需要判断的集合
* @return 集合非空时返回 true
*/
public static boolean listIsNotEmpty(Collection list){
return !listIsEmpty(list);
} /**
* 判断对象为null或空时
* @param object 对象
* @return 对象为空或null时返回 true
*/
public static boolean isEmpty(Object object) {
if (object == null) {
return (true);
}
if ("".equals(object)) {
return (true);
}
if ("null".equals(object)) {
return (true);
}
return (false);
} /**
* 判断对象非空
* @param object 对象
* @return 对象为非空时返回 true
*/
public static boolean isNotEmpty(Object object) {
if (object != null && !object.equals("") && !object.equals("null")) {
return (true);
}
return (false);
} public static void main(String[] args) {
TreeDto treeDto1 = new TreeDto("1","A",new ArrayList<TreeDto>());
TreeDto treeDto1_1 = new TreeDto("1.1","A-A",new ArrayList<TreeDto>());
TreeDto treeDto1_2 = new TreeDto("1.2","A-B",new ArrayList<TreeDto>());
TreeDto treeDto1_3 = new TreeDto("1.3","A-C",new ArrayList<TreeDto>());
treeDto1.getSubsetTreeDtoList().add(treeDto1_1);
treeDto1.getSubsetTreeDtoList().add(treeDto1_2);
treeDto1.getSubsetTreeDtoList().add(treeDto1_3); TreeDto treeDto2 = new TreeDto("2","B",new ArrayList<TreeDto>());
TreeDto treeDto2_1 = new TreeDto("2.1","B-A",new ArrayList<TreeDto>());
TreeDto treeDto2_2 = new TreeDto("2.2","B-B",new ArrayList<TreeDto>());
TreeDto treeDto2_3 = new TreeDto("2.3","B-C",new ArrayList<TreeDto>());
TreeDto treeDto2_3_1 = new TreeDto("2.3.1","B-C-A",null);
treeDto2.getSubsetTreeDtoList().add(treeDto2_1);
treeDto2.getSubsetTreeDtoList().add(treeDto2_2);
treeDto2.getSubsetTreeDtoList().add(treeDto2_3);
treeDto2.getSubsetTreeDtoList().get(2).getSubsetTreeDtoList().add(treeDto2_3_1); String[] array = {"1.3","2.2","2.3.1"};
List<String> idList = Arrays.asList(array);
List<TreeDto> treeDtoList = new ArrayList<>();
treeDtoList.add(treeDto1);
treeDtoList.add(treeDto2);
System.out.println(JSON.toJSONString(screenTree(treeDtoList,idList)));
}
}

返回结果为

java后端操作树结构的更多相关文章

  1. java后端程序员1年工作经验总结

    java后端1年经验和技术总结(1) 1.引言 毕业已经一年有余,这一年里特别感谢技术管理人员的器重,以及同事的帮忙,学到了不少东西.这一年里走过一些弯路,也碰到一些难题,也受到过做为一名开发却经常为 ...

  2. Spring+SpringMVC+MyBatis+easyUI整合进阶篇(二)RESTful API实战笔记(接口设计及Java后端实现)

    写在前面的话 原计划这部分代码的更新也是上传到ssm-demo仓库中,因为如下原因并没有这么做: 有些使用了该项目的朋友建议重新创建一个仓库,因为原来仓库中的项目太多,结构多少有些乱糟糟的. 而且这次 ...

  3. Java后端程序员都做些什么?

    这个问题来自于QQ网友,一句两句说不清楚,索性写个文章. 我刚开始做Web开发的时候,根本没有前端,后端之说. 原因很简单,那个时候服务器端的代码就是一切:接受浏览器的请求,实现业务逻辑,访问数据库, ...

  4. 以技术面试官的经验分享毕业生和初级程序员通过面试的技巧(Java后端方向)

    本来想分享毕业生和初级程序员如何进大公司的经验,但后来一想,人各有志,有程序员或许想进成长型或创业型公司或其它类型的公司,所以就干脆来分享些提升技能和通过面试的技巧,技巧我讲,公司你选,两厢便利. 毕 ...

  5. 最近面试 Java 后端开发的感受!

    阅读本文大概需要 4.3 分钟. 首发:cnblogs.com/JavaArchitect/p/10011253.html 上周,密集面试了若干位Java后端候选人,工作经验在3到5年间.我的标准其实 ...

  6. 最近面试java后端开发的感受:如果就以平时项目经验来面试,通过估计很难——再论面试前的准备

    在上周,我密集面试了若干位Java后端的候选人,工作经验在3到5年间.我的标准其实不复杂:第一能干活,第二Java基础要好,第三最好熟悉些分布式框架,我相信其它公司招初级开发时,应该也照着这个标准来面 ...

  7. Java后端学习,推荐书籍和学习路线

    最近在学习Java和全栈开发,推荐一些有用的书籍 书架主要针对Java后端和全栈开发用的 书籍介绍 <Spring Boot 2.0企业级应用开发实战> 本书深入浅岀地讲解了 Spring ...

  8. 面试经验合集-Java后端<一>

    面试一:CDKHXJSYJS   时间:2018-12-29 周六 地点:航天科技大厦32楼   一 技术题目 <回忆版> 1.上下转型 2.Java异常:分类.处理.设计 3.二叉排序树 ...

  9. Java后端面试的一切技巧和常见的问题经验总结

    原文地址:cnblogs.com/JavaArchitect/p/10011253.html 上周,密集面试了若干位Java后端候选人,工作经验在3到5年间.我的标准其实不复杂(适用90%小小小公司, ...

  10. java后端学习记录2019

    学习计划 2019年计划 1.学习计算机基础,并加以实践.包括LeetCode刷题.数据库原理(索引和锁.Sql优化等).网络协议(Http.Tcp).操作系统(加深Linux).<Http权威 ...

随机推荐

  1. Python中使用支付宝支付

    准备 # 支付宝文档 https://opendocs.alipay.com/open/270/105898?pathHash=b3b2b667 # 在沙箱环境下实名认证 https://openho ...

  2. 每日一题 力扣 1090 https://leetcode.cn/problems/largest-values-from-labels/

    每日一题 力扣 1090 https://leetcode.cn/problems/largest-values-from-labels/ 先对这道题目进行排序,贪心一下,要求分数最高的放在前面,而标 ...

  3. C语言指针--一级指针

    文章目录 前言 一.什么是指针 二.一级指针的使用 1.一级指针的创建 2.指针的赋值 3.&是什么 4.一维指针的使用 4.1 `变量` 和 `*变量` 4.2 输出指针变量内容 4.3 改 ...

  4. 更快的训练和推理: 对比 Habana Gaudi®2 和英伟达 A100 80GB

    通过本文,你将学习如何使用 Habana Gaudi2 加速模型训练和推理,以及如何使用 Optimum Habana 训练更大的模型.然后,我们展示了几个基准测例,包括 BERT 预训练.Stabl ...

  5. 牛客小白月赛64 C题 题解

    题目链接 题意描述 这一题的意思其实就是,让你构造一个\(n * k\)的矩阵,使得第 i 列的总和为 i ,同时使得:每一列的任意两个数之间的差不大于1,且任意两行之间的总和差不大于1. \(1 \ ...

  6. [grpc]双向tls加密认证

    前言 假设gRPC服务端的主机名为qw.er.com,需要为gRPC服务端和客户端之间的通信配置tls双向认证加密. 生成证书 生成ca根证书.生成过程会要求填写密码.CN.ON.OU等信息,记住密码 ...

  7. 从redis未授权访问到获取服务器权限

    从redis未授权访问到获取服务器权限 好久没写博客了,博客园快荒芜了.赶紧再写一篇,算是一个关于自己学习的简要的记录把. 这里是关于redis未授权访问漏洞的一篇漏洞利用: 首先是redis,靶场搭 ...

  8. CSS基础(4)

    目录 1 定位 1.1 为什么需要定位 1.2 定位组成 1.2.1 边偏移(方位名词) 1.2.2 定位模式 (position) 1.3 定位模式介绍 1.3.1 静态定位(static) - 了 ...

  9. xfs文件系统核心架构介绍

    版权声明:本文为CSDN博主「瞧见风」的原创文章,遵循CC 4.0 BY-SA版权协议原文链接:https://blog.csdn.net/scaleqiao/article/details/5209 ...

  10. 手把手教你搭建springbootsecurity+jwt,全面了解

    研究了两周了springbootsecurity+jwt的使用,终于搭起来了,这里跟大家分享下. 首先,不了解jwt的可以提前去查下相关资料,我之前也有讲过,大家可以先看下:  https://www ...