首页 > 编程语言 >java中List列表转成子父集列表

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

时间:2024-08-20 11:24:41浏览次数:13  
标签:Node 节点 List param 转成子 new 列表 id

一、前言

        在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.Collections;
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) || StringUtils.isBlank(sortNumber)) {
            return Collections.emptyList();
        }
        //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;
    }

}
  • 测试结果

标签:Node,节点,List,param,转成子,new,列表,id
From: https://blog.csdn.net/weixin_39865508/article/details/141231517

相关文章

  • 四:《Python基础语法汇总》— 列表&元组&集合
    一:列表​列表是Python中最基本的数据类型之一,是可以存放多个多种元素的容器​列表是Python中序列的一种,是一个有序可变序列​由于列表是可变序列,所以可以对其里面的内容进行修改,无需重新开辟空间存储1.下标与切片:​列表中也可以应用下标索引和切片,与在字符串中的应用......
  • show processlist查看Mysql当前正在运行的线程
    showprocesslistshowprocesslist;--或者SELECTid,db,user,host,command,time,state,infofrominformation_schema.PROCESSLISTWHERE1=1--andcommand!='Sleep'ANDHOSTLIKE'%localhost%'orderbytimedescID定义:每个连......
  • 原生JS实现虚拟列表
    什么是虚拟列表如果我们要将一个数组渲染为列表添加到页面中,我们可以很容易实现,无非就是循环遍历这个数组,然后依次创建DOM元素插入即可,但是如果数据量很庞大,比如有一万条数据,我们就要把一万个DOM结点插入到页面中,这显然会导致页面的卡顿。为了针对这个场景进行优化,让页面和我......
  • python列表方法-insert、pop、remove
    1.pop方法python中pop方法从列表中删除一个元素(默认是最后一个元素),并且返回这个元素a=[100,200,300,400]a.pop()400a[100,200,300]列表a调用pop方法,删除最后一个元素400返回。2.insert方法python中insert方法用于将一个对象插入列表a=[100,200,300,400]a.inse......
  • 解决nvm ls-remote 列表只出现iojs版本
    前言在nvm安装node时发现显示不存在此版本,使用nvmls-remote查看可安装列表时发现,列表中只有iojs$nvmls-remoteiojs-v1.0.0iojs-v1.0.1iojs-v1.0.2iojs-v1.0.3iojs-v1.0.4iojs-v1.1.0iojs-v1.2.0iojs-v1.3.0iojs-v1.4.1......
  • TCPIP路由技术第一卷 第三大部分-4 路由更新Distribute-list
    外部的路由可以进入到路由表中,路由表中的路由也可以被通告出去,那么路由过滤器正是通过管制这些出入路由表的路由来工作的.distributelisteigrpoutin方向完全满足ospfout方向不行r1:routerripnoautoversion2network12.0.0.0r2:routerripnoautoversion2ne......
  • TCPIP路由技术第一卷 第三大部分-5 Prefix-list和扩展ACL
    r1:routerripredistribute-listprefix1outs1/1ipprefix-list1permit44.1.1.0/24ipprefix-listnamepermit172.16.0.0/22ge24le24/22前缀22bit相同ge24掩码范围最小24位.当没有ge(172.16.0.0/22),掩码范围最小值跟前缀相同le24(172.16.0.0/22le24)掩码范......
  • vue列表渲染
    当model里面有多个数据需要再view中显示是,可以使用v-for指令来进行操作可以使用v-for指令基于一个数组来渲染一个列表,v-for指令需要使用iteminitems形式的特殊语法其中items是源数据数组,而item是被迭代的数组元素的别名语法:<开始标签v-for="自定义名称in/of数组/对象"></......
  • Java中ArrayList集合—基础详解(知识点+代码示例)
    ArrayList(集合)ArrayList(集合)ArrayList(集合)10.1ArrayList成员方法10.2集合练习10.2.1添加字符串10.2.2添加数字10.2.3添加学生对象并遍历10.2.4集合概述:集合可以直接存储引用数据类型,不能直接存储基本数据类型,如果要存储基本数据类型,需要将基本数据类型变成对......
  • 易优field获取channelartlist标签的字段值-EyouCms手册
    【基础用法】名称:field功能:获取channelartlist标签里的字段值,field标签只能在channelartlist标签里使用。语法:{eyou:channelartlisttypeid='栏目ID'type='son'row='20'}{eyou:fieldname='typename'/}{/eyou:channelartlist}参数:name=''字段名底......