树结构处理,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设计)
下载使用可视化大屏设计模板,减少重复性操作,提高报表制作效率的同时也确保了报表风格一致,凸显关键数据信息。 软件:奥威BI系统,又称奥威BI数据可视化工具 所属功能板块:主题皮肤上传下载(数…...
Spring Boot + Vue的网上商城之客服系统实现
Spring Boot Vue的网上商城之客服系统实现 在网上商城中,客服系统是非常重要的一部分,它能够为用户提供及时的咨询和解答问题的服务。本文将介绍如何使用Spring Boot和Vue.js构建一个简单的网上商城客服系统。 思路 在本教程中,我们学习了…...

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

记录一些奇怪的报错
错误:AttributeError: module distutils has no attribute version 解决方案: 第一步:pip uninstall setuptools 第二步:conda install setuptools58.0.4 错误: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、测试: 时间会比较长࿰…...
基于开源模型搭建实时人脸识别系统(五):人脸跟踪
继续填坑,之前已经讲了人脸检测,人脸识别实战之基于开源模型搭建实时人脸识别系统(二):人脸检测概览与模型选型_开源人脸识别模型_CodingInCV的博客-CSDN博客,人脸检测是定位出画面中人脸的位置,…...
VUE | 配置环境变量
本篇目录 1. 创建开发环境配置文件2. 创建正式环境配置文件3. 在代码中访问环境变量4. 加载环境变量 在 Vue 项目中是使用 .env 文件来定义和使用不同的环境变量,这些文件在 Vue 项目根目录下创建。推荐有几种环境就创建几个 .env 文件,下面就开发环境和…...

Dynamic-TP入门初探
背景 在使用线程池的过程中,会出现一些痛点: 代码中创建了一个线程池,但是不知道那几个核心参数设置多少比较合适。凭经验设置参数值,上线后发现需要调整,改代码重新发布服务,非常麻烦。线程池相对开发人…...
Git的基本操作:远程操作
7 Git的远程操作 远程操作主要是指,在不同的仓库之间进行提交和代码更改。是一个明显的对等的分布式系统。其中本地个仓库与远程仓库,不同的远程仓库之间都可以建立这种关系。这种关系之间的操作主要有pull和push。 远程仓库 创建SSH key远程仓库和本…...
【IOC,AOP】spring的基础概念
IOC 控制反转 对象的创建控制权转交给外部实体,就是控制反转。外部实体便是IOC容器。其实就是以前创建java对象都是我们new一下,现在我们可以把这个new交给IOC容器来做,new出来的对象也会交由IOC容器来管理。这个new出来的对象则称为Bean。 …...

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

1-4 AUTOSAR方法论
总目录——AUTOSAR入门详解AUTOSAR入门详解目录汇总:待续中。。。https://xianfan.blog.csdn.net/article/details/132818463 目录 一、前言 二、方法论 三、单个ECU开发流程 一、前言 汽车生产供应链上有以下角色:OEM、TIER1、TIER2,其主…...
MFC C++ 数据结构及相互转化 CString char * char[] byte PCSTR DWORE unsigned
CString: char * char [] BYTE BYTE [] unsigned char DWORD CHAR:单字节字符8bit WCHAR为Unicode字符:typedef unsigned short wchar_t TCHAR : 如果当前编译方式为ANSI(默认)方式,TCHAR等价于CHAR,如果为Unicode方式,…...

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

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

Matlab 如何计算正弦信号的幅值和初始相角
Matlab 如何计算正弦信号的幅值和初始相角 1、概述 如果已知一个正弦信号的幅值,在FFT后频域上该信号谱线的幅值与设置值不同,而是大了许多;如果不知道某一正弦信号的幅値,又如何通FFT后在頻域上求出该正弦信号的幅值呢? 2、…...
华为hcie认证培训报班培训好?还是自学好
华为HCIE认证培训报班培训和自学各有优势。 培训的优势: 系统性学习:培训课程通常会系统地涵盖HCIE认证所需的各个知识点,帮助你建立全面的理论体系。指导与互动:培训中,能够与资深讲师互动,及时解答疑惑…...

ASP.NET+sqlserver通用电子病历管理系统
一、源码描述 这是一款简洁十分美观的ASP.NETsqlserver源码,界面十分美观,功能也比较全面,比较适合 作为毕业设计、课程设计、使用,感兴趣的朋友可以下载看看哦 二、功能介绍 该源码功能十分的全面,具体介绍如下&…...

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

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
python打卡第47天
昨天代码中注意力热图的部分顺移至今天 知识点回顾: 热力图 作业:对比不同卷积层热图可视化的结果 def visualize_attention_map(model, test_loader, device, class_names, num_samples3):"""可视化模型的注意力热力图,展示模…...
ffmpeg(三):处理原始数据命令
FFmpeg 可以直接处理原始音频和视频数据(Raw PCM、YUV 等),常见场景包括: 将原始 YUV 图像编码为 H.264 视频将 PCM 音频编码为 AAC 或 MP3对原始音视频数据进行封装(如封装为 MP4、TS) 处理原始 YUV 视频…...