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

猫头虎的技术笔记:Spring Boot启动报错解决方案

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…...

Istio网关流量转发

摘要 Istio网关转发到后端服务的步骤&#xff0c;可以按照以下详细说明进行操作&#xff1a; 配置Istio Sidecar&#xff1a;确保目标后端服务已经部署并成功运行&#xff0c;并为其启用Istio Sidecar。Istio Sidecar负责在Pod中注入Istio代理&#xff0c;以便实现流量控制和…...

阿里云acp云计算认证考试科目有哪些?

阿里云ACP云计算认证考试科目包括以下内容&#xff1a; 阿里云云计算基础知识&#xff1a;包括云计算的定义、特点、服务模式、部署模式、虚拟化技术等相关知识。阿里云产品&#xff1a;包括阿里云ECS、RDS、SLB、OSS、DNS等核心产品的架构、使用方法、优化技巧等相关知识。云…...

8、Spring security配置放过的请求又被拦截了

项目场景&#xff1a; 在项目中有一些接口需要放开spring security拦截&#xff0c;配置方法如下&#xff0c;其中permitUrls为需要放过的请求路径。 Override public void configure(WebSecurity web) {web.ignoring().antMatchers(permitUrls); }问题描述 实际请求地址&am…...

4.后端·新建子模块与开发(传统模式)

文章目录 学习资料新建子模块与各层查询entity的列表entitymapper层service层controller层 测试 学习资料 https://www.bilibili.com/video/BV13g411Y7GS?p8&spm_id_frompageDriver&vd_sourceed09a620bf87401694f763818a31c91e b站的学习视频 新建子模块与各层 在r…...

.netcore 连接 apache doris

apache doris 兼容mysql协议&#xff1b;所以我们在.netcore项目中&#xff0c;可以使用Mysql的驱动 dotnet add package MySqlConnector 测试代码&#xff1a; [HttpGet]public async Task<string> Get2(){//打开连接await using var connection new MySqlConnectio…...

【C语言】探讨常见自定义类型的存储形式

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;C语言 &#x1f525;该文章将探讨结构体&#xff0c;位段&#xff0c;共用体的存储形式。 目录&#xff1a; &#x1f30d;结构体内存对齐✉…...

NLP(六十九)智能文档问答助手升级

本文在笔者之前研发的大模型智能文档问答项目中&#xff0c;开发更进一步&#xff0c;支持多种类型文档和URL链接&#xff0c;支持多种大模型接入&#xff0c;且使用更方便、高效。 项目介绍 在文章NLP&#xff08;六十一&#xff09;使用Baichuan-13B-Chat模型构建智能文档中…...

如何使用SQL系列 之 如何在MySQL中使用索引

引言 关系数据库可用于处理任何大小的数据&#xff0c;包括包含数百万行的大型数据库。结构化查询语言(SQL)提供了一种基于特定条件在数据库表中查找特定行的简洁而直接的方法。随着数据库变得越来越大&#xff0c;在其中找到特定的行变得越来越困难&#xff0c;就像大海捞针一…...

数字孪生相关政策梳理,重点对各行业版块的指导和引领

前言 数字孪生技术作为新型智慧城市建设的创新引领性技术&#xff0c;有利于打造孪生城市运行空间&#xff0c;强化城市大脑基础能力&#xff0c;实现全域时空数据融合。数字孪生技术在推动智慧城市建设方面的作用已越来越受到重视。2021年3月&#xff0c;《国家“十四五”规划…...

沈阳做网站客户多吗/网址收录入口

defaultExpandAll:autoExpandParent"true":treeData"treeData"select"this.onSelect"/>data () {return {// expandedKeys: [0-0-0, 0-0-1], // 受控展开指定的树节点autoExpandParent: true, // 是否自动展开父节点// checkedKeys: [0-0-0],…...

哪个网站可以做条形码/杭州哪家seo公司好

转载请标明出处&#xff1a;http://blog.csdn.net/lmj623565791/article/details/30993277 今天偶然发现电脑里面还有这种一个样例。感觉效果还不错&#xff0c;不记得啥时候下载的了。也好久没上w3cfuns了&#xff0c;怀念学习前台的日子&#xff0c;给大家分享下。 效果图&am…...

手机网页游戏排行榜2021前十名/杭州优化公司多少钱

参加过校招的同学,应该对外包有一定的了解了。基本上我们听过的企业都有外包岗,很多同学也在校招的过程中拿到过外包offer。 现在很多大型公司为了节省成本,将一些偏重劳动量,而非技术量的工作,都选择外包给第三方公司来做,这就导致了现在外包公司发展越来越兴。如果接到…...

生成手机网站/扬州百度推广公司

麒麟天气是一款程序开源的天气预报软件。通过获取实时权威气象数据信息&#xff0c;让使用者可以随意查看全国各地未来7天内的天气状况。下面就为大家简单的介绍一下麒麟天气的主要功能。安装编程开发依赖包&#xff1a;$ sudo apt install debhelper (>9) qtbase5-dev qt5-…...

在线教育网站开发时长/营销培训方案

随着后互联网时代行业分工越来越细化&#xff0c;用户数据的海量涌向&#xff0c;数据的采集、分析成为了解产品趋势、判断竞争对手与个性化推荐的重要一环&#xff0c;爬虫因此成为了许多用人单位招聘要求的必备技能!那么爬虫是什么&#xff1f;学习来简单吗&#xff1f;相信刚…...

网易做相册旅游网站/买链接网

文/金金 首发于一周进步每到期末&#xff0c;都是大作业和报告的高发季&#xff0c;一个“死线”刚过&#xff0c;另一堆“死线”接踵而至。作为一名在报告的海洋里中挣扎&#xff0c;妄图顺利存活的同学&#xff0c;我自然是使用链接到样式的多级列表&#xff0c;Word自动化排…...