码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 树结构处理,list和tree互转


    1、实体类

    1. package com.iot.common.test.entity;
    2. import lombok.Data;
    3. import java.util.List;
    4. /**
    5. * @description:
    6. * @author:zilong
    7. * @date:2023/9/8
    8. */
    9. @Data
    10. public class Node {
    11. //id
    12. private String id;
    13. //父节点id
    14. private String pId;
    15. //名称
    16. private String name;
    17. //编码
    18. private String code;
    19. //层级
    20. private String level;
    21. private List children;
    22. public Node(String id, String pId, String name, String code, String level) {
    23. this.id = id;
    24. this.pId = pId;
    25. this.name = name;
    26. this.code = code;
    27. this.level = level;
    28. }
    29. public Node() {
    30. }
    31. }

    2、工具类

    1. package com.iot.common.util;
    2. import com.alibaba.fastjson.JSON;
    3. import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
    4. import com.iot.common.test.entity.Node;
    5. import lombok.SneakyThrows;
    6. import java.lang.invoke.SerializedLambda;
    7. import java.lang.reflect.Method;
    8. import java.util.ArrayList;
    9. import java.util.HashMap;
    10. import java.util.List;
    11. import java.util.Map;
    12. import java.util.function.BiConsumer;
    13. import java.util.function.Function;
    14. import java.util.stream.Collectors;
    15. /**
    16. * 树工具类
    17. */
    18. public class TreeUtil {
    19. /**
    20. * 基础数据转树结构Map版本(速度比递归要快很多)
    21. *
    22. * @param sourceList 需转换的数据
    23. * @param getId 主键
    24. * @param getParentId 父id (父id必须和主键相同类型)
    25. * @param getChildren 子集
    26. * @param setChildren 子集
    27. * @return tree
    28. */
    29. public static List listToTree(List sourceList, Function getId, Function getParentId,
    30. Function> getChildren, BiConsumer> setChildren) {
    31. Map oldMap = sourceList.stream().collect(Collectors.toMap(getId, T -> T));
    32. List treeList = new ArrayList<>();
    33. sourceList.forEach(tree -> {
    34. T parent = oldMap.get(getParentId.apply(tree));
    35. if (parent == null) {
    36. treeList.add(tree);
    37. } else {
    38. List ch = getChildren.apply(parent);
    39. if (ch == null) {
    40. ch = new ArrayList<>();
    41. }
    42. ch.add(tree);
    43. setChildren.accept(parent, ch);
    44. }
    45. });
    46. return treeList;
    47. }
    48. /**
    49. * 树结构转父子排序列表且按父在前,子在后,进行排序。
    50. *
    51. * @param treeList 父子树列表(带有id、parentId和children的模型列表)
    52. * @param getId
    53. * @param getParentId
    54. * @param getChildren
    55. * @param setChildren
    56. * @param
    57. * @param
    58. * @return
    59. */
    60. public static List treeListToSortList(List treeList, Function getId, Function getParentId,
    61. Function> getChildren, BiConsumer> setChildren) {
    62. // 先整成树形结构
    63. List list = listToTree(treeList, getId, getParentId, getChildren, setChildren);
    64. List sortList = new ArrayList<>();
    65. tree2List(sortList, list.get(0), getChildren, setChildren);
    66. return sortList;
    67. }
    68. /**
    69. * 树结构转列表
    70. *
    71. * @param result 结果容器
    72. * @param t 树顶部元素
    73. * @param getChildren
    74. * @param
    75. */
    76. private static void tree2List(List result, T t, Function> getChildren, BiConsumer> setChildren) {
    77. //根据条件判断是否需要添加至列表
    78. result.add(t);
    79. List children = getChildren.apply(t);
    80. // 将children置成空
    81. setChildren.accept(t, null);
    82. //没有子级
    83. if (children == null || children.size() == 0) {
    84. return;
    85. }
    86. //存在子级,递归调用
    87. for (T child : children) {
    88. tree2List(result, child, getChildren, setChildren);
    89. }
    90. }
    91. /**
    92. * 基础数据集转树结构
    93. *
    94. * @param baseList 树结构的基础数据集
    95. * @param getIdFn 获取主键的函数
    96. * @param getParentIdFn 获取父节点的函数
    97. * @param getChildrenFn 获取子集的函数
    98. * @param t
    99. * @param r
    100. * @return t
    101. */
    102. @SneakyThrows
    103. public static List treeOut(List baseList, Function getIdFn, Function getParentIdFn, SFunction getChildrenFn) {
    104. /*所有元素的Id*/
    105. List ids = baseList.stream().map(getIdFn).collect(Collectors.toList());
    106. /*查出所有顶级节点*/
    107. List topLevel = baseList.stream().filter(x -> {
    108. R apply = getParentIdFn.apply(x);
    109. return !ids.contains(apply);
    110. }).collect(Collectors.toList());
    111. return TreeUtil.recursion(topLevel, baseList, getIdFn, getParentIdFn, getChildrenFn);
    112. }
    113. /**
    114. * 指定顶级元素的基础数据集转树结构
    115. *
    116. * @param list
    117. * @param top
    118. * @param getIdFn
    119. * @param getParentIdFn
    120. * @param getChildrenFn
    121. * @param
    122. * @param
    123. * @return
    124. */
    125. @SneakyThrows
    126. public static List treeOutWithTop(List list, T top, Function getIdFn, Function getParentIdFn, SFunction getChildrenFn) {
    127. ArrayList ts = new ArrayList<>();
    128. ts.add(top);
    129. return TreeUtil.recursion(ts, list, getIdFn, getParentIdFn, getChildrenFn);
    130. }
    131. @SneakyThrows
    132. private static List recursion(List superLevel, List list, Function getIdFn, Function getParentIdFn, SFunction getChildrenFn) {
    133. //获取setChildren的Method
    134. Method writeReplaceMethod = getChildrenFn.getClass().getDeclaredMethod("writeReplace");
    135. boolean accessible = writeReplaceMethod.isAccessible();
    136. writeReplaceMethod.setAccessible(true);
    137. SerializedLambda serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(getChildrenFn);
    138. writeReplaceMethod.setAccessible(accessible);
    139. String setMethodName = serializedLambda.getImplMethodName().replaceFirst("g", "s");
    140. Method setMethod = Class.forName(serializedLambda.getImplClass().replace("/", ".")).getDeclaredMethod(setMethodName, List.class);
    141. for (T t : superLevel) {
    142. List children = list.stream().filter(x -> {
    143. R apply = getParentIdFn.apply(x);
    144. R apply1 = getIdFn.apply(t);
    145. return apply.equals(apply1);
    146. }).collect(Collectors.toList());
    147. if (children.size() <= 0) {
    148. continue;
    149. }
    150. List recursion = recursion(children, list, getIdFn, getParentIdFn, getChildrenFn);
    151. setMethod.invoke(t, recursion);
    152. }
    153. return superLevel;
    154. }
    155. /**
    156. * 将列表转换为树形结构
    157. * 注:此方法的根节点的pid需要为null
    158. *
    159. * @param nodeList 列表
    160. * @return 树形结构
    161. */
    162. public static List buildTree(List nodeList) {
    163. // 存储所有节点
    164. Map nodeMap = new HashMap<>(nodeList.size());
    165. // 存储根节点
    166. List rootList = new ArrayList<>();
    167. // 将所有节点存储到map中,并找出根节点
    168. for (Node node : nodeList) {
    169. nodeMap.put(node.getId(), node);
    170. if (node.getPId() == null) {
    171. rootList.add(node);
    172. }
    173. }
    174. // 遍历所有节点,将子节点添加到父节点的children中
    175. for (Node node : nodeList) {
    176. String pId = node.getPId();
    177. if (pId != null) {
    178. Node parentNode = nodeMap.get(pId);
    179. if (parentNode != null) {
    180. if (parentNode.getChildren() == null) {
    181. parentNode.setChildren(new ArrayList<>());
    182. }
    183. parentNode.getChildren().add(node);
    184. }
    185. }
    186. }
    187. return rootList;
    188. }
    189. public static void main(String[] args) {
    190. ArrayList list = new ArrayList() {
    191. {
    192. add(new Node("1", "0", "A", "1", "1"));
    193. add(new Node("2", "0", "B", "2", "1"));
    194. add(new Node("3", "1", "A-1", "11", "2"));
    195. add(new Node("4", "1", "A-2", "12", "2"));
    196. add(new Node("5", "3", "A-1-1", "111", "3"));
    197. add(new Node("6", "5", "A-1-1-1", "1111", "4"));
    198. add(new Node("7", "6", "A-1-1-1-1", "11111", "5"));
    199. add(new Node("8", "2", "B-1", "21", "2"));
    200. add(new Node("9", "8", "B-1-1", "211", "3"));
    201. add(new Node("10", "9", "B-1-1-1", "2111", "4"));
    202. }
    203. };
    204. //使用工具类 treeOut:
    205. List result = TreeUtil.treeOut(list, Node::getId, Node::getPId, Node::getChildren);
    206. System.out.println("-----【treeOut】-----");
    207. System.out.println(JSON.toJSONString(result));
    208. //使用工具类 listToTree(Map):
    209. List result1 = TreeUtil.listToTree(list, Node::getId, Node::getPId, Node::getChildren, Node::setChildren);
    210. System.out.println("-----【listToTree】-----");
    211. System.out.println(JSON.toJSONString(result1));
    212. //使用工具类 treeOutWithTop:
    213. Node top = new Node();
    214. top.setId("3");
    215. List result2 = TreeUtil.treeOutWithTop(list, top, Node::getId, Node::getPId, Node::getChildren);
    216. System.out.println("-----【treeOutWithTop】-----");
    217. System.out.println(JSON.toJSONString(result2));
    218. //使用工具类 buildTree:
    219. List result3 = TreeUtil.buildTree(list);
    220. System.out.println("-----【buildTree】-----");
    221. System.out.println(JSON.toJSONString(result3));
    222. }
    223. }
    224. 相关阅读:
      最新Java面试真题,备战金九银十。
      一文看懂Transformer(详解)
      【工作实践-06】uniapp使用webView
      【vSphere 8 自签名证书】企业 CA 签名证书替换 vSphere Machine SSL 证书Ⅰ—— 生成 CSR
      视频讲解|含可再生能源的热电联供型微网经济运行优化(含确定性和源荷随机两部分代码)
      specCPU 2006 备忘
      Maven基础知识【基本概念、项目结构、依赖管理、生命周期与插件】
      【Qt】Qt5.15、Qt6在线安装(使用国内源)
      c++ 深度拷贝和浅拷贝
      热点报告 | 解压经济成为新风向,素人改造踩中用户痛点
    225. 原文地址:https://blog.csdn.net/supersolon/article/details/132823433
      • 最新文章
      • 攻防演习之三天拿下官网站群
        数据安全治理学习——前期安全规划和安全管理体系建设
        企业安全 | 企业内一次钓鱼演练准备过程
        内网渗透测试 | Kerberos协议及其部分攻击手法
        0day的产生 | 不懂代码的"代码审计"
        安装scrcpy-client模块av模块异常,环境问题解决方案
        leetcode hot100【LeetCode 279. 完全平方数】java实现
        OpenWrt下安装Mosquitto
        AnatoMask论文汇总
        【AI日记】24.11.01 LangChain、openai api和github copilot
      • 热门文章
      • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
        奉劝各位学弟学妹们,该打造你的技术影响力了!
        五年了,我在 CSDN 的两个一百万。
        Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
        面试官都震惊,你这网络基础可以啊!
        你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
        心情不好的时候,用 Python 画棵樱花树送给自己吧
        通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
        13 万字 C 语言从入门到精通保姆级教程2021 年版
        10行代码集2000张美女图,Python爬虫120例,再上征途
      Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
      正则表达式工具 cron表达式工具 密码生成工具

      京公网安备 11010502049817号