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

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...