当前位置: 首页 > 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地址将数据包仅发送到…...

Python中的生成器和迭代器:原理与实践

Python中的生成器和迭代器&#xff1a;原理与实践 一、背景与动机 在Python编程中&#xff0c;处理大量数据时&#xff0c;内存管理是一个常见的挑战。生成器&#xff08;Generators&#xff09;和迭代器&#xff08;Iterators&#xff09;为解决这一问题提供了一种高效的方式&…...

终极指南:5个实用技巧解决Rainmeter开发中的内存保护异常问题

终极指南&#xff1a;5个实用技巧解决Rainmeter开发中的内存保护异常问题 【免费下载链接】rainmeter Desktop customization tool for Windows 项目地址: https://gitcode.com/gh_mirrors/ra/rainmeter 在Rainmeter桌面定制工具的开发过程中&#xff0c;内存保护异常&a…...

UE5 RPG开发实战:用接口轻松搞定鼠标悬停敌人描边(含完整蓝图与C++代码)

UE5 RPG开发实战&#xff1a;用接口实现敌人悬停描边的高效方案 在动作角色扮演游戏&#xff08;ARPG&#xff09;开发中&#xff0c;清晰的交互反馈是提升玩家体验的关键环节。当玩家将鼠标悬停在敌人身上时&#xff0c;如何直观地标识当前选中的目标&#xff1f;本文将深入探…...

快速找回Chrome密码:ChromePass终极使用指南

快速找回Chrome密码&#xff1a;ChromePass终极使用指南 【免费下载链接】chromepass Get all passwords stored by Chrome on WINDOWS. 项目地址: https://gitcode.com/gh_mirrors/chr/chromepass 你是否曾经因为忘记Chrome浏览器中保存的重要登录密码而感到困扰&#…...

从图像分割到GAN生成:转置卷积(Transpose Conv)的两种实战配置与调参心得

转置卷积实战指南&#xff1a;图像分割与GAN生成中的核心技巧 在计算机视觉领域&#xff0c;我们常常需要将低分辨率特征图恢复到原始尺寸——无论是为了像素级预测的图像分割任务&#xff0c;还是从潜在空间生成逼真图像的GAN模型。传统插值方法如双线性插值虽然简单&#xff…...

3分钟快速上手:免费高效的Elasticsearch可视化工具Elasticvue终极指南

3分钟快速上手&#xff1a;免费高效的Elasticsearch可视化工具Elasticvue终极指南 【免费下载链接】elasticvue Elasticsearch gui for the browser 项目地址: https://gitcode.com/gh_mirrors/el/elasticvue 你是否曾经为复杂的Elasticsearch集群管理而烦恼&#xff1f…...

Unity 工具之(SharpZipLib)跨平台中文Zip压缩与解压实战指南(附多线程优化)

1. 为什么选择SharpZipLib处理Unity中的Zip文件 在Unity项目开发中&#xff0c;资源打包和网络传输经常需要处理压缩文件。SharpZipLib作为.NET平台的老牌压缩库&#xff0c;相比Unity内置的压缩方案有三个不可替代的优势&#xff1a; 首先是对中文路径的完美支持。很多开发者都…...

MicroOS:Arduino轻量级任务调度内核详解

1. MicroOS&#xff1a;面向Arduino的轻量级任务管理内核概述MicroOS是一个专为Arduino平台设计的极简型实时任务管理器&#xff0c;其核心定位并非替代FreeRTOS或Zephyr等完整RTOS&#xff0c;而是填补Arduino原生loop()单线程模型在多任务调度、精确定时与事件解耦方面的空白…...

用LDA模型挖掘微信聊天秘密:Gensim实战教程(含pyLDAvis可视化)

用LDA模型挖掘微信聊天秘密&#xff1a;Gensim实战教程&#xff08;含pyLDAvis可视化&#xff09; 微信聊天记录中隐藏着大量有价值的信息&#xff0c;从日常对话到重要决策&#xff0c;这些文本数据就像一座未被充分挖掘的金矿。本文将带你用Python中的Gensim库构建LDA主题模型…...

Phi-4-Reasoning-Vision基础教程:双卡4090环境安装、镜像拉取与端口映射

Phi-4-Reasoning-Vision基础教程&#xff1a;双卡4090环境安装、镜像拉取与端口映射 1. 环境准备与快速部署 在开始之前&#xff0c;请确保您的系统满足以下要求&#xff1a; 硬件配置&#xff1a;至少两张NVIDIA RTX 4090显卡&#xff08;24GB显存&#xff09;软件环境&…...