首页 > 编程语言 >Java集合List转树结构工具类-函数版

Java集合List转树结构工具类-函数版

时间:2023-06-05 14:33:32浏览次数:32  
标签:Java 树结构 list List add new My getIdFn


  • 工具类:
package com.example.mindsa.util.tree;

import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.SneakyThrows;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 树形工具类-函数版
 *
 * @author sunziwen
 */

public class TreeUtil {
    /**
     * @param list          树结构的基础数据集
     * @param getIdFn       获取主键的函数
     * @param getParentIdFn 获取父节点的函数
     * @param getChildrenFn 获取子集的函数
     * @param <T>           t
     * @param <R>           r
     * @return t
     */
    @SneakyThrows
    public static <T, R> List<T> treeOut(List<T> list, Function<T, R> getIdFn, Function<T, R> getParentIdFn, SFunction<T, R> getChildrenFn) {
        /*所有元素的Id*/
        List<Object> ids = list.stream().map(getIdFn).collect(Collectors.toList());
        /*查出所有顶级节点*/
        List<T> topLevel = list.stream().filter(x -> {
            R apply = getParentIdFn.apply(x);
            return !ids.contains(apply);
        }).collect(Collectors.toList());
        return TreeUtil.recursion(topLevel, list, getIdFn, getParentIdFn, getChildrenFn);
    }


    @SneakyThrows
    private static <T, R> List<T> recursion(List<T> superLevel, List<T> list, Function<T, R> getIdFn, Function<T, R> getParentIdFn, SFunction<T, R> getChildrenFn) {
        //获取setChildren的Method
        Method writeReplaceMethod = getChildrenFn.getClass().getDeclaredMethod("writeReplace");
        boolean accessible = writeReplaceMethod.isAccessible();
        writeReplaceMethod.setAccessible(true);
        SerializedLambda serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(getChildrenFn);
        writeReplaceMethod.setAccessible(accessible);
        String setMethodName = serializedLambda.getImplMethodName().replaceFirst("g", "s");
        Method setMethod = Class.forName(serializedLambda.getImplClass().replace("/", ".")).getDeclaredMethod(setMethodName, List.class);

        for (T t : superLevel) {
            List<T> children = list.stream().filter(x -> {
                R apply = getParentIdFn.apply(x);
                R apply1 = getIdFn.apply(t);
                return apply.equals(apply1);
            }).collect(Collectors.toList());
            if (children.size() <= 0) {
                continue;
            }

            List<T> recursion = recursion(children, list, getIdFn, getParentIdFn, getChildrenFn);
            setMethod.invoke(t, recursion);
        }
        return superLevel;
    }


}

 

  • 使用示例:
public static void main(String[] args) {
        //模拟数据
        ArrayList<My> list = new ArrayList<My>() {{
            add(new My("1", "-1", "a"));
            add(new My("2", "-1", "aa"));
            add(new My("3", "1", "b"));
            add(new My("4", "1", "c"));
            add(new My("5", "3", "d"));
            add(new My("6", "5", "e"));
            add(new My("7", "6", "f"));
            add(new My("8", "2", "g"));
            add(new My("9", "8", "h"));
            add(new My("10", "9", "i"));
        }};

        //使用工具类:
        List<My> result = TreeUtil.treeOut(list, My::getUserid, My::getPId, My::getChs);
        //打印
        System.out.println(JSON.toJSONString(result));
    }

标签:Java,树结构,list,List,add,new,My,getIdFn
From: https://blog.51cto.com/u_14121041/6415447

相关文章

  • Java反射获取不到注解
    在CGlib动态代理的情况下method.getAnnotation(PostMapping.class);这样是获取不到注解的.需要用Spring自带的工具类来获取:AnnotationUtils.findAnnotation(method,PostMapping.class);......
  • Java模拟表单提交编码不同导致乱码问题解决
    最近有个业务需要模拟表单提交到asp页面中,但是我的项目编码是UTF8,而asp页面是GB2312,中文字段提交后,到达数据库后是乱码.问题的解决在于模拟提交的时候指定编码:我用的HTTP框架是Unirest,代码如下:......
  • Redis系列14:使用List实现消息队列
    Redis系列1:深刻理解高性能Redis的本质Redis系列2:数据持久化提高可用性Redis系列3:高可用之主从架构Redis系列4:高可用之Sentinel(哨兵模式)Redis系列5:深入分析Cluster集群模式追求性能极致:Redis6.0的多线程模型追求性能极致:客户端缓存带来的革命Redis系列8:Bitmap实现亿万级......
  • CMakeLists.txt 编写模板
     新建文件  CMakeLists.txt #设置cmake的最低版本cmake_minimum_required(VERSION2.8)#指定为C++11版本set(CMAKE_CXX_STANDARD11)#设置工程名称project(wss)message(${PROJECT_SOURCE_DIR})set(SRC_LIST${PROJECT_SOURCE_DIR}/src/websocket_s......
  • java 图形学 点和闭合区域位置关系判断
    判断一个点是否在一个特定的区域内或外,通常需要你具备区域的数学表达(例如,方程、不等式等)以及要判断的点的坐标。例如,如果你有一个圆的方程(x-h)²+(y-k)²=r²,其中(h,k)是圆心,r是半径,你要判断点(a,b)是否在此圆内或外。你可以将点(a,b)的坐标带入这个方程:如果(a......
  • JavaScript 递归的简单例子
     typescript+vue3functionflattenTree(tree:any,result:any){tree.forEach((node:any)=>{result.push({id:node.id,cat_name:node.cat_name,cat_name_en:node.cat_name_en});if(node.child.length>0){flattenTree(node.child,r......
  • Java的先行发生原则
    先行发生原则(Happens-Before)是Java内存模型定义的一个等效判断原则。依赖这个原则,我们可以通过几条简单规则判断数据是否存在竞争,线程是否安全,而不需要陷入Java内存模型苦涩难懂的定义之中。“先行发生”原则指的是什么。比如说操作A先行发生于操作B,其实就是说在操作B发生......
  • java 内存模型
    java内存模型(memorymodel)定义了java虚拟机如何与计算机内存交互。JVM将内存主要分为栈(stack)内存和堆(heap)内存。每当我们声明新的变量和对象、调用新的方法、声明String或执行类似的操作时,JVM都会从堆栈内存或堆空间为这些操作指定内存。每个线程有自己的栈内存,是线程独有的。堆......
  • java 自己写分页
    longcurrent=1;longsize=100;StringcurrentOther=jsonObject.getStr("current");if(StrUtil.isNotBlank(currentOther)){//?:0或1个,*:0或多个,+:1或多个BooleanstrResult1=currentOther.matches("^[-\\+]?([0-9]+\\.?)?[0-9]+$");if......
  • Java中Double除保留后小数位的几种方法
     返回double型的1.能四舍五入doubled=114.145;d=(double)Math.round(d*100)/100;System.out.println(d); 2.BigDecimal.ROUND_HALF_UP表示四舍五入,BigDecimal.ROUND_HALF_DOWN也是五舍六入,BigDecimal.ROUND_UP表示进位处理(就是直接加1),BigDecimal.ROUND_DOWN表示直接......