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

news2024/9/21 12:40:18

一、前言

        在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.遍历树list
        treeList.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;
    }

}
  • 测试结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2042477.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机械行业数字化生产供应链产品解决方案(十二)

我们为机械行业提供的数字化生产供应链解决方案通过集成物联网、人工智能和大数据技术&#xff0c;打造了一套智能化的生产和供应链管理系统&#xff0c;实现了从设计、生产到物流的全程数字化、智能化。该系统通过实时数据采集与分析&#xff0c;优化生产计划和资源配置&#…

mybatis批量修改问题

update 表名称 set version version 1, update_time NOW(), basket_price case when id1130254 then 0.00 end, basket_spec_name case when id1130254 then “名称1” when id1130255 then “名称” end where id IN ( 1130254 , 1130255); 为什么 id为 1130255 的 baske…

Halcon 算子汇总

gen_tuple_const(1000,1.5) 生成一个长度为1000&#xff0c;里面每一个数组元素都为1.5的数组 gen_tuple_const(100,chr(ord(a) 1)) 生成一个长度为100&#xff0c;里面每一个数组元素都为b的数组 ord函数是库函数&#xff0c;用于获取字符的ASCII值 chr(ord(a) 1) 结…

算法设计与分析(快速幂算法

目录 1. 题目&#xff1a;2. 代码&#xff1a;2.1边界条件处理2.2分治策略2.3合并结果2.4递归终止条件2.5效率分析 小结&#xff1a; 1. 题目&#xff1a; 2. 代码&#xff1a; #include<iostream> using namespace std;int pow(int x, int n){// 边界条件 if (x 0) re…

大数据技术——实战项目:广告数仓(第七部分)数仓工作流调度实操

目录 第12章 广告数仓全流程调度 12.2 新数据生成 12.2.1 广告监测日志 12.2.2 广告管理平台数据 12.3 工作流调度实操 12.3.1 DolphinScheduler集群模式 12.3.2 DolphinScheduler单机模式 第12章 广告数仓全流程调度 12.1 调度工具Dolphinscheduler DolphinScheduler…

鸿蒙HarmonyOS:应用程序开发与使用-延迟加载(lazy import)

随着应用程序功能的不断扩展&#xff0c;冷启动所需的时间显著增长&#xff0c;主要是由于在启动初期加载了大量模块&#xff0c;其中存在大量未被实际执行的冗余文件。这种情形不仅拖延了应用的初始化过程&#xff0c;还造成了资源的无效占用。亟需采取措施精简加载流程&#…

解决IDEA-HTTP状态500-内部服务器错误

目录 背景: 解决过程: MySQL的优点和缺点: 背景: 类型异常报告 消息无法打开Hibernate会话进行事务处理&#xff1b;嵌套异常是org.hibernate.exception.GenericJDBCException:无法连接 描述服务器遇到了意外情况&#xff0c;导致无法满足请求等等.... 在运行项目的时候&…

Linux中以单容器部署Nginx+ASP.NET Core

强烈推荐在生产环境中使用反向代理服务器转发请求到Kestrel Http服务器&#xff0c;本文将会实践将Nginx --->ASP.NET Core 部署架构容器化的过程。 Nginx->ASP.NET Coe部署架构容器化 在Docker中部署Nginx--->ASP.NETCore 有两种选择&#xff0c; 第一种是在单容器…

【Java】解析方法的调用关系

目录 一、方法的定义二、方法的声明格式三、方法的调用四、特殊方法&#xff1a;程序入口main方法五、方法的局部变量六、类的静态变量七、类的静态方法八、方法的传参九、方法的重载 一、方法的定义 方法就是 将功能重复的代码封装成一段独立的代码&#xff0c;通过调用方法的…

Element Plus的el-carousel走马灯平铺多张图片

效果 <template><div class"system-banner"><el-carousel height"320px" indicator-position"outside" :autoplay"false"><el-carousel-item v-for"(item, index) in govList" :key"index"…

「VLM」CLIP 文本与图像的桥梁

github&#xff1a;https://github.com/OpenAI/CLIP paper&#xff1a;Learning Transferable Visual Models From Natural Language Supervision CLIP全称&#xff1a;Contrastive Language-Imge Pre-training&#xff0c;即对比语言-图像预训练。 对比学习是一种更关注于学习…

SD卡无法读取怎么办?4个修复方法千万别错过

SD卡是我们生活中常见的存储设备之一&#xff0c;它小巧方便&#xff0c;容量适中&#xff0c;被广泛应用于数码相机、手机、平板等设备中&#xff0c;随着时间的增长&#xff0c;有时会遇到突然无法读取的问题&#xff0c;这不仅会影响我们的数据访问&#xff0c;还可能造成数…

idea 中的properties文件中文乱码

如遇到以下类似的问题&#xff1a; 配置setting中-》Editor-》File Encodings 中&#xff0c;将以下三处位置的编码格式进行修改 Global Encoding GBK Project Encoding GBK Default encoding for properties files UTF-8 修改之后文件的中文显示正常

MySQl 中对数据表的增删改查(基础)

MySQl 中对数据表的增删改查&#xff08;基础&#xff09; 新增演示插入一条数据插入多条数据 查询全列查询部分列查询查询关于列名的表达式查询时用别名查询去重后的结果查询排序后的结果条件查询比较运算符和逻辑运算符 分页查询 修改删除 黑白图是在命令行里的&#xff0c;彩…

【题解】【枚举】—— [NOIP1997 普及组] 棋盘问题

【题解】【枚举】—— [NOIP1997 普及组] 棋盘问题 [NOIP1997 普及组] 棋盘问题题目背景题目描述输入格式输出格式输入输出样例输入 #1输出 #1 解法1解法2 [NOIP1997 普及组] 棋盘问题 戳我查看题目&#xff08;洛谷&#xff09; 题目背景 NOIP1997 普及组第一题 题目描述 …

Java基础 文字小游戏

souf System.out.printf("你好啊%s","张三") 输出你好啊张三 System.out.printn()放在中间可以换行 System.out.printf("%s你好啊%s","张三","李四") 输出 张三你好啊李四 只有输出没有换行效果。 制作一个文字小游戏…

每期一个小窍门: Goland 配置跳板机登陆

写简单点 先说下大概流程 本地 访问 localhost:6000 --> 转发到跳板机:22 --> 再转发到指定内网地址 本机 .ssh/config Host *ControlPersist yesControlMaster autoControlPath ~/.ssh/%n:%p本机公钥 copy 到跳板机 和内网被跳机 本机命令 ssh -N -f -L 6000:<内…

Linux基础入门---安装vmware

&#x1f600;前言 本篇博文是关于Linux基础入门和vmwarel5.5下载&#xff0c;希望你能够喜欢。 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;您的满意是我的动…

告别繁琐ppt制作,用这5款AI工具,一键生成轻松搞定!

在云办公逐渐成为主流的当下&#xff0c;许多职场人士在办公时会首选各类在线应用&#xff0c;最常见的就是在线制作PPT、在线编辑文档、在线编辑表格或智能表格&#xff0c;除此之外&#xff0c;这两年AI人工智能技术的发展&#xff0c;也诞生了许多能一键生成PPT的AI工具。 …

队列的实现及循环队列

一、队列的概念及结构 队列只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表。队列具有先进先出FIFO&#xff08;Fist In First Out&#xff09;。 入队列&#xff1a;进行插入操作的一端称为队尾。 出队列&#xff1a;进行删除操作的一端称为…