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

树结构处理,list和tree互转

1、实体类

package com.iot.common.test.entity;import lombok.Data;import java.util.List;/*** @description:* @author:zilong* @date:2023/9/8*/
@Data
public class Node {//idprivate String id;//父节点idprivate String pId;//名称private String name;//编码private String code;//层级private String level;private List<Node> children;public Node(String id, String pId, String name, String code, String level) {this.id = id;this.pId = pId;this.name = name;this.code = code;this.level = level;}public Node() {}
}

2、工具类

package com.iot.common.util;import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.iot.common.test.entity.Node;
import lombok.SneakyThrows;import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;/*** 树工具类*/public class TreeUtil {/*** 基础数据转树结构Map版本(速度比递归要快很多)** @param sourceList  需转换的数据* @param getId       主键* @param getParentId 父id (父id必须和主键相同类型)* @param getChildren 子集* @param setChildren 子集* @return tree*/public static <T, R> List<T> listToTree(List<T> sourceList, Function<T, R> getId, Function<T, R> getParentId,Function<T, List<T>> getChildren, BiConsumer<T, List<T>> setChildren) {Map<R, T> oldMap = sourceList.stream().collect(Collectors.toMap(getId, T -> T));List<T> treeList = new ArrayList<>();sourceList.forEach(tree -> {T parent = oldMap.get(getParentId.apply(tree));if (parent == null) {treeList.add(tree);} else {List<T> ch = getChildren.apply(parent);if (ch == null) {ch = new ArrayList<>();}ch.add(tree);setChildren.accept(parent, ch);}});return treeList;}/*** 树结构转父子排序列表且按父在前,子在后,进行排序。** @param treeList    父子树列表(带有id、parentId和children的模型列表)* @param getId* @param getParentId* @param getChildren* @param setChildren* @param <T>* @param <R>* @return*/public static <T, R> List<T> treeListToSortList(List<T> treeList, Function<T, R> getId, Function<T, R> getParentId,Function<T, List<T>> getChildren, BiConsumer<T, List<T>> setChildren) {// 先整成树形结构List<T> list = listToTree(treeList, getId, getParentId, getChildren, setChildren);List<T> sortList = new ArrayList<>();tree2List(sortList, list.get(0), getChildren, setChildren);return sortList;}/*** 树结构转列表** @param result      结果容器* @param t           树顶部元素* @param getChildren* @param <T>*/private static <T> void tree2List(List<T> result, T t, Function<T, List<T>> getChildren, BiConsumer<T, List<T>> setChildren) {//根据条件判断是否需要添加至列表result.add(t);List<T> children = getChildren.apply(t);// 将children置成空setChildren.accept(t, null);//没有子级if (children == null || children.size() == 0) {return;}//存在子级,递归调用for (T child : children) {tree2List(result, child, getChildren, setChildren);}}/*** 基础数据集转树结构** @param baseList      树结构的基础数据集* @param getIdFn       获取主键的函数* @param getParentIdFn 获取父节点的函数* @param getChildrenFn 获取子集的函数* @param <T>           t* @param <R>           r* @return t*/@SneakyThrowspublic static <T, R> List<T> treeOut(List<T> baseList, Function<T, R> getIdFn, Function<T, R> getParentIdFn, SFunction<T, R> getChildrenFn) {/*所有元素的Id*/List<Object> ids = baseList.stream().map(getIdFn).collect(Collectors.toList());/*查出所有顶级节点*/List<T> topLevel = baseList.stream().filter(x -> {R apply = getParentIdFn.apply(x);return !ids.contains(apply);}).collect(Collectors.toList());return TreeUtil.recursion(topLevel, baseList, getIdFn, getParentIdFn, getChildrenFn);}/*** 指定顶级元素的基础数据集转树结构** @param list* @param top* @param getIdFn* @param getParentIdFn* @param getChildrenFn* @param <T>* @param <R>* @return*/@SneakyThrowspublic static <T, R> List<T> treeOutWithTop(List<T> list, T top, Function<T, R> getIdFn, Function<T, R> getParentIdFn, SFunction<T, R> getChildrenFn) {ArrayList<T> ts = new ArrayList<>();ts.add(top);return TreeUtil.recursion(ts, list, getIdFn, getParentIdFn, getChildrenFn);}@SneakyThrowsprivate 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的MethodMethod 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;}/*** 将列表转换为树形结构* 注:此方法的根节点的pid需要为null** @param nodeList 列表* @return 树形结构*/public static List<Node> buildTree(List<Node> nodeList) {// 存储所有节点Map<String, Node> nodeMap = new HashMap<>(nodeList.size());// 存储根节点List<Node> rootList = new ArrayList<>();// 将所有节点存储到map中,并找出根节点for (Node node : nodeList) {nodeMap.put(node.getId(), node);if (node.getPId() == null) {rootList.add(node);}}// 遍历所有节点,将子节点添加到父节点的children中for (Node node : nodeList) {String pId = node.getPId();if (pId != null) {Node parentNode = nodeMap.get(pId);if (parentNode != null) {if (parentNode.getChildren() == null) {parentNode.setChildren(new ArrayList<>());}parentNode.getChildren().add(node);}}}return rootList;}public static void main(String[] args) {ArrayList<Node> list = new ArrayList<Node>() {{add(new Node("1", "0", "A", "1", "1"));add(new Node("2", "0", "B", "2", "1"));add(new Node("3", "1", "A-1", "11", "2"));add(new Node("4", "1", "A-2", "12", "2"));add(new Node("5", "3", "A-1-1", "111", "3"));add(new Node("6", "5", "A-1-1-1", "1111", "4"));add(new Node("7", "6", "A-1-1-1-1", "11111", "5"));add(new Node("8", "2", "B-1", "21", "2"));add(new Node("9", "8", "B-1-1", "211", "3"));add(new Node("10", "9", "B-1-1-1", "2111", "4"));}};//使用工具类 treeOut:List<Node> result = TreeUtil.treeOut(list, Node::getId, Node::getPId, Node::getChildren);System.out.println("-----【treeOut】-----");System.out.println(JSON.toJSONString(result));//使用工具类 listToTree(Map):List<Node> result1 = TreeUtil.listToTree(list, Node::getId, Node::getPId, Node::getChildren, Node::setChildren);System.out.println("-----【listToTree】-----");System.out.println(JSON.toJSONString(result1));//使用工具类 treeOutWithTop:Node top = new Node();top.setId("3");List<Node> result2 = TreeUtil.treeOutWithTop(list, top, Node::getId, Node::getPId, Node::getChildren);System.out.println("-----【treeOutWithTop】-----");System.out.println(JSON.toJSONString(result2));//使用工具类 buildTree:List<Node> result3 = TreeUtil.buildTree(list);System.out.println("-----【buildTree】-----");System.out.println(JSON.toJSONString(result3));}}

相关文章:

树结构处理,list和tree互转

1、实体类 package com.iot.common.test.entity;import lombok.Data;import java.util.List;/*** description:* author:zilong* date:2023/9/8*/ Data public class Node {//idprivate String id;//父节点idprivate String pId;//名称private String name;//编码private Stri…...

可视化大屏设计模板 | 主题皮肤(报表UI设计)

下载使用可视化大屏设计模板&#xff0c;减少重复性操作&#xff0c;提高报表制作效率的同时也确保了报表风格一致&#xff0c;凸显关键数据信息。 软件&#xff1a;奥威BI系统&#xff0c;又称奥威BI数据可视化工具 所属功能板块&#xff1a;主题皮肤上传下载&#xff08;数…...

Spring Boot + Vue的网上商城之客服系统实现

Spring Boot Vue的网上商城之客服系统实现 在网上商城中&#xff0c;客服系统是非常重要的一部分&#xff0c;它能够为用户提供及时的咨询和解答问题的服务。本文将介绍如何使用Spring Boot和Vue.js构建一个简单的网上商城客服系统。 思路 在本教程中&#xff0c;我们学习了…...

RabbitMQ: return机制

1. Return机制 Confirm只能保证消息到达exchange&#xff0c;无法保证消息可以被exchange分发到指定queue。 而且exchange是不能持久化消息的&#xff0c;queue是可以持久化消息。 采用Return机制来监听消息是否从exchange送到了指定的queue中 2.Java的实现方式 1.导入依赖 &l…...

记录一些奇怪的报错

错误&#xff1a;AttributeError: module distutils has no attribute version 解决方案&#xff1a; 第一步&#xff1a;pip uninstall setuptools 第二步&#xff1a;conda install setuptools58.0.4 错误&#xff1a;ModuleNotFoundError: No module named _distutils_hac…...

Ubuntu 安装redis数据库,并设置开机自启动

1、下载安装包 wget http://download.redis.io/releases/redis-7.0.9.tar.gz 2、解压 tar -zxvf redis-7.0.9.tar.gz 3、复制到解压缩的包移动到/usr/local/ sudo mv ./redis-7.0.9 /usr/local/ 4、编译 cd /usr/local/redis-7.0.9 sudo make 5、测试: 时间会比较长&#xff0…...

基于开源模型搭建实时人脸识别系统(五):人脸跟踪

继续填坑&#xff0c;之前已经讲了人脸检测&#xff0c;人脸识别实战之基于开源模型搭建实时人脸识别系统&#xff08;二&#xff09;&#xff1a;人脸检测概览与模型选型_开源人脸识别模型_CodingInCV的博客-CSDN博客&#xff0c;人脸检测是定位出画面中人脸的位置&#xff0c…...

VUE | 配置环境变量

本篇目录 1. 创建开发环境配置文件2. 创建正式环境配置文件3. 在代码中访问环境变量4. 加载环境变量 在 Vue 项目中是使用 .env 文件来定义和使用不同的环境变量&#xff0c;这些文件在 Vue 项目根目录下创建。推荐有几种环境就创建几个 .env 文件&#xff0c;下面就开发环境和…...

Dynamic-TP入门初探

背景 在使用线程池的过程中&#xff0c;会出现一些痛点&#xff1a; 代码中创建了一个线程池&#xff0c;但是不知道那几个核心参数设置多少比较合适。凭经验设置参数值&#xff0c;上线后发现需要调整&#xff0c;改代码重新发布服务&#xff0c;非常麻烦。线程池相对开发人…...

Git的基本操作:远程操作

7 Git的远程操作 远程操作主要是指&#xff0c;在不同的仓库之间进行提交和代码更改。是一个明显的对等的分布式系统。其中本地个仓库与远程仓库&#xff0c;不同的远程仓库之间都可以建立这种关系。这种关系之间的操作主要有pull和push。 远程仓库 创建SSH key远程仓库和本…...

【IOC,AOP】spring的基础概念

IOC 控制反转 对象的创建控制权转交给外部实体&#xff0c;就是控制反转。外部实体便是IOC容器。其实就是以前创建java对象都是我们new一下&#xff0c;现在我们可以把这个new交给IOC容器来做&#xff0c;new出来的对象也会交由IOC容器来管理。这个new出来的对象则称为Bean。 …...

安全实战 | 怎么用零信任防范弱密码?

防范弱密码&#xff0c;不仅需要提升安全性&#xff0c;更需要提升用户体验。 比如在登录各类业务系统时&#xff0c;我们希望员工登录不同系统不再频繁切换账号密码&#xff0c;不再需要3-5个月更换一次密码&#xff0c;也不再需要频繁的输入、记录、找回密码。 员工所有的办…...

1-4 AUTOSAR方法论

总目录——AUTOSAR入门详解AUTOSAR入门详解目录汇总&#xff1a;待续中。。。https://xianfan.blog.csdn.net/article/details/132818463 目录 一、前言 二、方法论 三、单个ECU开发流程 一、前言 汽车生产供应链上有以下角色&#xff1a;OEM、TIER1、TIER2&#xff0c;其主…...

MFC C++ 数据结构及相互转化 CString char * char[] byte PCSTR DWORE unsigned

CString&#xff1a; char * char [] BYTE BYTE [] unsigned char DWORD CHAR&#xff1a;单字节字符8bit WCHAR为Unicode字符:typedef unsigned short wchar_t TCHAR : 如果当前编译方式为ANSI(默认)方式&#xff0c;TCHAR等价于CHAR&#xff0c;如果为Unicode方式&#xff0c…...

多版本CUDA安装切换

系统中默认的安装CUDA为12.0&#xff0c;现在需要在个人用户下安装CUDA11.7。 CUDA 下载 CUDA官网下载 安装 Log file not open.Segmentation fault (core dumped)错误 将/tmp/cuda-installer.log删除即可。重新安装&#xff0c;去掉驱动的安装&#xff0c;设置Toolkit的安装…...

sqlserver union和union all 的区别

1.首先在数据库编辑1-40数字&#xff1b; 2.查询Num<30的数据&#xff0c;查询Num>20 and Num<40的数据&#xff0c;使用union all合并&#xff1b; 发现30-20的数字重复了&#xff0c;可见union all 不去重&#xff1b; 3.查询Num<30的数据&#xff0c;查询Num…...

Matlab 如何计算正弦信号的幅值和初始相角

Matlab 如何计算正弦信号的幅值和初始相角 1、概述 如果已知一个正弦信号的幅值&#xff0c;在FFT后频域上该信号谱线的幅值与设置值不同&#xff0c;而是大了许多&#xff1b;如果不知道某一正弦信号的幅値&#xff0c;又如何通FFT后在頻域上求出该正弦信号的幅值呢? 2、…...

华为hcie认证培训报班培训好?还是自学好

华为HCIE认证培训报班培训和自学各有优势。 培训的优势&#xff1a; 系统性学习&#xff1a;培训课程通常会系统地涵盖HCIE认证所需的各个知识点&#xff0c;帮助你建立全面的理论体系。指导与互动&#xff1a;培训中&#xff0c;能够与资深讲师互动&#xff0c;及时解答疑惑…...

ASP.NET+sqlserver通用电子病历管理系统

一、源码描述 这是一款简洁十分美观的ASP.NETsqlserver源码&#xff0c;界面十分美观&#xff0c;功能也比较全面&#xff0c;比较适合 作为毕业设计、课程设计、使用&#xff0c;感兴趣的朋友可以下载看看哦 二、功能介绍 该源码功能十分的全面&#xff0c;具体介绍如下&…...

wireshark通常无法抓取交换机所有端口报文

Wireshark 是一种网络分析工具&#xff0c;它通常在计算机的网络接口上进行数据包捕获和分析。然而&#xff0c;Wireshark 默认情况下无法直接捕获交换机所有端口的报文。 交换机是一种网络设备&#xff0c;它在局域网内转发数据包&#xff0c;根据目的MAC地址将数据包仅发送到…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI

前一阵子在百度 AI 开发者大会上&#xff0c;看到基于小智 AI DIY 玩具的演示&#xff0c;感觉有点意思&#xff0c;想着自己也来试试。 如果只是想烧录现成的固件&#xff0c;乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外&#xff0c;还提供了基于网页版的 ESP LA…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...

用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法

用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法 大家好,我是Echo_Wish。最近刷短视频、看直播,有没有发现,越来越多的应用都开始“懂你”了——它们能感知你的情绪,推荐更合适的内容,甚至帮客服识别用户情绪,提升服务体验。这背后,神经网络在悄悄发力,撑起…...