当前位置: 首页 > news >正文

java中List列表转成子父集列表

一、前言

        在Java中,如果你有一个表示父子关系的列表,并且想要把这个列表转成一个子父集list列表树目录,一般来说想要把list列表转成一个子父集列表,这个对象需要在属性中必须要有几个字段,id(节点id)、parentId(指向父节点id)、children(子节点),通过三个字段可以组装成一个子父集列表目录。

二、代码示例

  • 创建Node节点对象类
package com.demo.terrutils;import lombok.Data;import java.util.List;/*** 文件名:Node* 创建者:* 创建时间:* 描述:*/
@Data
public class Node {/*** id*/private String id;/*** 名称*/private String name;/*** 父id*/private String parentId;/*** 排序字段*/private Integer sortNumber;/*** 子节点*/private List<Node> children;
}
  • 创建TreeUtil工具类
package com.demo.terrutils;import io.micrometer.common.util.StringUtils;import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;/*** 文件名:TreeUtil* 创建者:* 创建时间:* 描述:list列表转子父节点列表工具类*/
public final class TreeUtil {//私有化构造,防止客户端通过 new 创建工具对象private TreeUtil(){}/*** 获取当前节点列表及子节点* @param list  集合列表* @param id    节点id值* @return* @param <T>*/public static <T> List<T> buildTreeByMap(List<T> list,String id) {//要求这个 <T> 泛型对象中的属性必须要和 id、parentId、children、sortNumber 保持名称一样return buildTreeByMap(list, "id", "parentId", "children","sortNumber", id);}/*** 通过 stream map 分组方式构建树* @param list          列表* @param idName        id名称* @param parentIdName  父id名称* @param childrenName  子节点列表名称* @param sortNumber    排序字段* @param root          顶层节点父id的值* @return* @param <T>*/public static <T> List<T> buildTreeByMap(List<T> list, String idName, String parentIdName, String childrenName,String sortNumber ,String root) {if (StringUtils.isBlank(idName) || StringUtils.isBlank(parentIdName) || StringUtils.isBlank(childrenName)) {return new ArrayList<>();}//1.排序分组Map<String, List<T>> mapList = list.stream()//根据sortNumber字段排序.sorted(Comparator.comparing(o-> (Integer)getFieldValue(o, sortNumber),//如果 sortNumber 字段为 null 则放在最后,不加这个会直接抛出异常Comparator.nullsLast(Integer::compareTo)))//根据parentId进行分组.collect(Collectors.groupingBy(o -> getFieldValue(o, parentIdName).toString()));//2.给每个节点设置子节点列表list.forEach(node -> setFieldValue(node, mapList.get(getFieldValue(node, idName).toString()), childrenName));//3.这个排序是因为返回的是多个根节点,需要单独在重新排序下List<T> treeList = list.stream().filter(o -> root.equals(getFieldValue(o, parentIdName))).sorted(Comparator.comparing(o-> (Integer)getFieldValue(o, sortNumber),Comparator.nullsLast(Integer::compareTo))).collect(Collectors.toList());return treeList;}/*** 获取属性值* @param o         对象* @param fieldName 属性名* @return {@link String}*/private static Object getFieldValue(Object o, String fieldName) {try {Class<?> oClass = o.getClass();Field field = oClass.getDeclaredField(fieldName);field.setAccessible(true);return field.get(o);} catch (NoSuchFieldException | IllegalAccessException e) {throw new RuntimeException(e);}}/*** 设置字段值* @param o         对象* @param val       值* @param fieldName 属性名*/private static void setFieldValue(Object o, Object val, String fieldName) {try {Class<?> oClass = o.getClass();Field field = oClass.getDeclaredField(fieldName);field.setAccessible(true);field.set(o, val);} catch (NoSuchFieldException | IllegalAccessException e) {throw new RuntimeException(e);}}}
  • 创建Main测试类
package com.demo.terrutils;import java.util.ArrayList;
import java.util.List;/*** 文件名:Main* 创建者:* 创建时间:* 描述:*/
public class Main {public static void main(String[] args) {//1.初始化列表List<Node> listNode = intListTest();//2.列表转为子父列表树结构List<Node> treeList = TreeUtil.buildTreeByMap(listNode,"0");//3.遍历树listtreeList.stream().forEach(node->{traverseNode(node);});}public static void traverseNode(Node node) {if (node == null) {return;}// 处理当前节点,例如打印节点信息System.out.println(node.getName() + " 排序字段 " +node.getSortNumber());// 如果存在子节点,递归遍历每个子节点if (node.getChildren() != null && !node.getChildren().isEmpty()) {for (Node child : node.getChildren()) {traverseNode(child);}}}private static List<Node> intListTest(){List<Node> nodeTestList = new ArrayList<>();Node test = new Node();test.setId("1");test.setParentId("0");test.setName("第一层1");test.setSortNumber(9);Node test1 = new Node();test1.setId("2");test1.setParentId("0");test1.setName("第一层2");test1.setSortNumber(7);Node test2 = new Node();test2.setId("3");test2.setParentId("0");test2.setName("第一层3");test2.setSortNumber(8);Node test3 = new Node();test3.setId("01");test3.setName("  第二层1");test3.setParentId("1");test3.setSortNumber(7);Node test4 = new Node();test4.setId("02");test4.setName("  第二层2");test4.setParentId("1");test4.setSortNumber(5);Node test5 = new Node();test5.setId("03");test5.setName("  第二层3");test5.setParentId("2");test5.setSortNumber(2);Node test6 = new Node();test6.setId("001");test6.setName("   第三层1");test6.setParentId("01");test6.setSortNumber(12);Node test7 = new Node();test7.setId("002");test7.setName("   第三层2");test7.setParentId("01");test7.setSortNumber(23);Node test8 = new Node();test8.setId("003");test8.setName("   第三层3");test8.setParentId("03");test8.setSortNumber(17);Node test9 = new Node();test9.setId("004");test9.setName("   第三层4");test9.setParentId("03");test9.setSortNumber(2);nodeTestList.add(test);nodeTestList.add(test1);nodeTestList.add(test2);nodeTestList.add(test3);nodeTestList.add(test4);nodeTestList.add(test5);nodeTestList.add(test6);nodeTestList.add(test7);nodeTestList.add(test8);nodeTestList.add(test9);return nodeTestList;}}
  • 测试结果

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 一口气把halcon的所有运算符说清楚
  • python爬虫滑块验证及各种加密函数(基于ddddocr进行的一层封装)
  • 什么是NLP实体识别?
  • 群晖NAS本地搭建可远程交互的大型语言模型LLM聊天机器人
  • Redis 列表类型的常用命令总结
  • WebService基础学习
  • SQL每日一练-0814
  • Unity新输入系统结构概览
  • telegraf、influxdb、grafana安装配置
  • Android的Service和Thread的区别
  • 将pytorch配置到jupyter里面(个人踩坑向)
  • HarmonyOS开发案例:创建全局自定义组件复用池-BuilderNode
  • 网鼎杯-2018-Web-Unfinish
  • python从入门到精通:函数
  • 安企CMS多站点迁移教程
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • 【个人向】《HTTP图解》阅后小结
  • avalon2.2的VM生成过程
  • docker-consul
  • Fastjson的基本使用方法大全
  • HTTP--网络协议分层,http历史(二)
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • in typeof instanceof ===这些运算符有什么作用
  • Js基础知识(四) - js运行原理与机制
  • js写一个简单的选项卡
  • Meteor的表单提交:Form
  • MYSQL 的 IF 函数
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • mysql中InnoDB引擎中页的概念
  • Python socket服务器端、客户端传送信息
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • Vue ES6 Jade Scss Webpack Gulp
  • 编写符合Python风格的对象
  • 系统认识JavaScript正则表达式
  • 新版博客前端前瞻
  • 智能合约Solidity教程-事件和日志(一)
  • AI算硅基生命吗,为什么?
  • k8s使用glusterfs实现动态持久化存储
  • ​iOS安全加固方法及实现
  • ‌前端列表展示1000条大量数据时,后端通常需要进行一定的处理。‌
  • # 透过事物看本质的能力怎么培养?
  • # 职场生活之道:善于团结
  • #13 yum、编译安装与sed命令的使用
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • (16)Reactor的测试——响应式Spring的道法术器
  • (LNMP) How To Install Linux, nginx, MySQL, PHP
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (四)linux文件内容查看
  • (一)SvelteKit教程:hello world
  • (转)EOS中账户、钱包和密钥的关系
  • (转)为C# Windows服务添加安装程序