当前位置:   article > 正文

Java实现树数据Tree与List互转并逐级汇总节点的值(支持树节点多列统计)_java 中list向上汇总金额

java 中list向上汇总金额

主要需求:a.实现树Tree与List互转   b.Tree实现多列统计数据汇总。前度采用MiniUI。

逐级汇总数据:找到最小节点,然后回溯其所有父节点,注意值的重复计算问题。

构造一棵树的基本节点:

  1. package com.example.demo.tree;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. /**
  5. * @ClassName: TreeNode
  6. * @Description: TODO(树的节点对象)
  7. * @author: pengjunlin
  8. * @motto: 学习需要毅力,那就秀毅力
  9. * @date 2019-06-18 23:35
  10. */
  11. public class TreeNode {
  12. /**
  13. * 节点ID
  14. */
  15. private long id;
  16. /**
  17. * 显示名称
  18. */
  19. private String label;
  20. /**
  21. * 当前节点的唯一值
  22. */
  23. private double value;
  24. /**
  25. * 当前节点的多个值的表达方式
  26. */
  27. private double[] multiValues=new double[]{};
  28. /**
  29. * 汇总单个节点的多个值
  30. */
  31. private List<Double> values=new ArrayList<Double>();
  32. /**
  33. * 当前节点所有子节点的值集合
  34. */
  35. private List<double []> childrenMultiValues=new ArrayList<double []>();
  36. /**
  37. * 父节点ID
  38. */
  39. private long pid;
  40. /**
  41. * 子节点集合对象
  42. */
  43. private List<TreeNode> children=new ArrayList<TreeNode>();
  44. /**
  45. * 是否计算本身
  46. */
  47. private boolean addSelf=false;
  48. public long getId() {
  49. return id;
  50. }
  51. public void setId(long id) {
  52. this.id = id;
  53. }
  54. public String getLabel() {
  55. return label;
  56. }
  57. public void setLabel(String label) {
  58. this.label = label;
  59. }
  60. public double getValue() {
  61. return value;
  62. }
  63. public void setValue(double value) {
  64. this.value = value;
  65. }
  66. public double[] getMultiValues() {
  67. return multiValues;
  68. }
  69. public void setMultiValues(double[] multiValues) {
  70. this.multiValues = multiValues;
  71. }
  72. public List<Double> getValues() {
  73. return values;
  74. }
  75. public void setValues(List<Double> values) {
  76. this.values = values;
  77. }
  78. public List<double[]> getChildrenMultiValues() {
  79. return childrenMultiValues;
  80. }
  81. public void setChildrenMultiValues(List<double[]> childrenMultiValues) {
  82. this.childrenMultiValues = childrenMultiValues;
  83. }
  84. public long getPid() {
  85. return pid;
  86. }
  87. public void setPid(long pid) {
  88. this.pid = pid;
  89. }
  90. public List<TreeNode> getChildren() {
  91. return children;
  92. }
  93. public void setChildren(List<TreeNode> children) {
  94. this.children = children;
  95. }
  96. public boolean isAddSelf() {
  97. return addSelf;
  98. }
  99. public void setAddSelf(boolean addSelf) {
  100. this.addSelf = addSelf;
  101. }
  102. }

构造树管理工具:

  1. package com.example.demo.tree;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.List;
  5. import java.util.Map;
  6. /**
  7. * @ClassName: TreeManager
  8. * @Description: TODO(树结构数据管理-实践验证)
  9. * @author: pengjunlin
  10. * @motto: 学习需要毅力,那就秀毅力
  11. * @date 2019-06-18 23:47
  12. */
  13. public class TreeManager {
  14. /**
  15. * 将List转成tree结构数据
  16. * @param list
  17. * @param rootId 默认顶级节点ID
  18. * @return
  19. */
  20. public static List<TreeNode> listToTree(List<TreeNode> list,long rootId){
  21. List<TreeNode> tree=new ArrayList<TreeNode>();
  22. Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
  23. // 将所有的数据,以键值对的形式装入map中
  24. for (TreeNode node : list) {
  25. // 去除冗余的子节点
  26. node.setChildren(new ArrayList<TreeNode>());
  27. map.put(node.getId(), node);
  28. }
  29. for (TreeNode node : list) {
  30. // 如果id是父级的话就放入tree中
  31. if (node.getId() == rootId) {
  32. tree.add(node);
  33. } else {
  34. // 子级通过父id获取到父级的类型
  35. TreeNode parent = map.get(node.getPid());
  36. // 父级获得子级,再将子级放到对应的父级中
  37. if(parent!=null){
  38. parent.getChildren().add(node);
  39. }
  40. }
  41. }
  42. return tree;
  43. }
  44. /**
  45. * 将tree结构数据转成List结构
  46. * @param list
  47. * @return
  48. */
  49. public static void treeToList(TreeNode node,List<TreeNode> list){
  50. if(list==null){
  51. list=new ArrayList<TreeNode>();
  52. }
  53. //设置当前节点的必要数据
  54. TreeNode nodeValue=new TreeNode();
  55. nodeValue.setId(node.getId());
  56. nodeValue.setLabel(node.getLabel());
  57. nodeValue.setValue(node.getValue());
  58. nodeValue.setMultiValues(node.getMultiValues());
  59. nodeValue.setChildrenMultiValues(node.getChildrenMultiValues());
  60. nodeValue.setPid(node.getPid());
  61. nodeValue.setChildren(new ArrayList<TreeNode>());
  62. list.add(nodeValue);
  63. //遍历递归子节点
  64. if(node.getChildren().size()>0){
  65. for (int i = 0; i < node.getChildren().size(); i++) {
  66. TreeNode node_= node.getChildren().get(i);
  67. treeToList(node_,list);
  68. }
  69. }
  70. }
  71. /**
  72. * 转换数据格式并设置对应节点的值汇总到根节点
  73. * @param list
  74. * @param rootId
  75. * @return
  76. */
  77. public static List<TreeNode> listToTreeWithSingleValue(List<TreeNode> list,long rootId){
  78. Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
  79. // 将所有的数据,以键值对的形式装入map中
  80. for (TreeNode node : list) {
  81. // 去除冗余的子节点
  82. node.setChildren(new ArrayList<TreeNode>());
  83. map.put(node.getId(), node);
  84. }
  85. List<TreeNode> tree=listToTree(list,rootId);
  86. /* // 存储最小子节点ID
  87. Map<Long,Object> leafList=new HashMap<Long,Object>();
  88. findMinNodes(tree.get(0),leafList,0);
  89. // 设置每个节点的值
  90. for (Long id_: leafList.keySet()) {
  91. // 内部递归树的父节点层级多于2会存在重复计算
  92. setParentNodeValue(map,id_);
  93. }*/
  94. // 存储最小子节点ID
  95. Map<Long,Object> leaf=new HashMap<Long,Object>();
  96. findMinNodes(tree.get(0),leaf);
  97. // 逐级设置父节点的值
  98. setValuesToParentNode(leaf, map);
  99. // 汇总所有节点的值
  100. double total=0;
  101. for (TreeNode node:map.values() ) {
  102. total=0;
  103. for (double value: node.getValues() ) {
  104. total+=value;
  105. }
  106. node.setValue(total);
  107. map.put(node.getId(),node);
  108. }
  109. List<TreeNode> result=new ArrayList<TreeNode>();
  110. for (TreeNode node:map.values()) {
  111. result.add(node);
  112. }
  113. return listToTree(result,rootId);
  114. }
  115. /**
  116. * 转换数据格式并设置对应节点的值汇总到根节点
  117. * @param tree
  118. * @return
  119. */
  120. public static List<TreeNode> treeToListWithSingleValue(TreeNode tree){
  121. List<TreeNode> list=new ArrayList<TreeNode>();
  122. // 获取到List
  123. treeToList(tree,list);
  124. Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
  125. // 将所有的数据,以键值对的形式装入map中
  126. for (TreeNode node : list) {
  127. // 去除冗余的子节点
  128. node.setChildren(new ArrayList<TreeNode>());
  129. map.put(node.getId(), node);
  130. }
  131. /* // 存储最小子节点ID
  132. Map<Long,Object> leafList=new HashMap<Long,Object>();
  133. findMinNodes(tree,leafList,0);
  134. // 设置每个节点的值
  135. for (Long id_: leafList.keySet()) {
  136. // 内部递归树的父节点层级多于2会存在重复计算
  137. setParentNodeValue(map,id_);
  138. }*/
  139. // 存储最小子节点ID
  140. Map<Long,Object> leaf=new HashMap<Long,Object>();
  141. findMinNodes(tree,leaf);
  142. // 逐级设置父节点的值
  143. setValuesToParentNode(leaf, map);
  144. // 汇总所有节点的值
  145. double total=0;
  146. for (TreeNode node:map.values() ) {
  147. total=0;
  148. for (double value: node.getValues() ) {
  149. total+=value;
  150. }
  151. node.setValue(total);
  152. map.put(node.getId(),node);
  153. }
  154. List<TreeNode> result=new ArrayList<TreeNode>();
  155. for (TreeNode node:map.values()) {
  156. result.add(node);
  157. }
  158. return result;
  159. }
  160. /**
  161. * 转换数据格式并设置对应节点的值汇总到根节点
  162. * @param list
  163. * @param rootId
  164. * @param columns
  165. * @return
  166. */
  167. public static List<TreeNode> listToTreeWithMultiValues(List<TreeNode> list,long rootId,int columns){
  168. Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
  169. // 将所有的数据,以键值对的形式装入map中
  170. for (TreeNode node : list) {
  171. // 去除冗余的子节点
  172. node.setChildren(new ArrayList<TreeNode>());
  173. map.put(node.getId(), node);
  174. }
  175. List<TreeNode> tree=listToTree(list,rootId);
  176. /* // 存储最小子节点ID
  177. Map<Long,Object> leafList=new HashMap<Long,Object>();
  178. findMinNodes(tree.get(0),leafList,0);
  179. // 设置每个节点的值
  180. for (Long id_: leafList.keySet()) {
  181. // 内部递归树的父节点层级多于2会存在重复计算
  182. setParentNodeMultiValues(map,id_);
  183. }*/
  184. // 存储最小子节点ID
  185. Map<Long,Object> leaf=new HashMap<Long,Object>();
  186. findMinNodes(tree.get(0),leaf);
  187. // 逐级追加父节点的值
  188. setMultiValuesToParentNode(leaf, map);
  189. // 汇总所有节点的值
  190. double [] valueColumns=null;
  191. for (TreeNode node:map.values() ) {
  192. valueColumns=new double[columns];
  193. for (double [] values: node.getChildrenMultiValues() ) {
  194. for (int i = 0,j=values.length; i < j; i++) {
  195. valueColumns[i]+=values[i];
  196. }
  197. }
  198. node.setMultiValues(valueColumns);
  199. map.put(node.getId(),node);
  200. }
  201. List<TreeNode> result=new ArrayList<TreeNode>();
  202. for (TreeNode node:map.values()) {
  203. result.add(node);
  204. }
  205. return listToTree(result,rootId);
  206. }
  207. /**
  208. * 转换数据格式并设置对应节点的值汇总到根节点
  209. * @param tree
  210. * @param columns
  211. * @return
  212. */
  213. public static List<TreeNode> treeToListWithMultiValues(TreeNode tree,int columns){
  214. List<TreeNode> list=new ArrayList<TreeNode>();
  215. // 获取到List
  216. treeToList(tree,list);
  217. Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
  218. // 将所有的数据,以键值对的形式装入map中
  219. for (TreeNode node : list) {
  220. // 去除冗余的子节点
  221. node.setChildren(new ArrayList<TreeNode>());
  222. map.put(node.getId(), node);
  223. }
  224. /*
  225. // 存储最小子节点ID
  226. Map<Long,Object> leafList=new HashMap<Long,Object>();
  227. findMinNodes(tree,leafList,0);
  228. // 设置每个节点的值
  229. for (Long id_: leafList.keySet()) {
  230. // 内部递归树的父节点层级多于2会存在重复计算
  231. setParentNodeMultiValues(map,id_);
  232. }*/
  233. // 存储最小子节点ID
  234. Map<Long,Object> leaf=new HashMap<Long,Object>();
  235. findMinNodes(tree,leaf);
  236. // 逐级追加父节点的值
  237. setMultiValuesToParentNode(leaf, map);
  238. // 汇总所有节点的值
  239. double [] valueColumns=null;
  240. for (TreeNode node:map.values() ) {
  241. valueColumns=new double[columns];
  242. for (double [] values: node.getChildrenMultiValues() ) {
  243. for (int i = 0,j=values.length; i < j; i++) {
  244. valueColumns[i]+=values[i];
  245. }
  246. }
  247. node.setMultiValues(valueColumns);
  248. map.put(node.getId(),node);
  249. }
  250. List<TreeNode> result=new ArrayList<TreeNode>();
  251. for (TreeNode node:map.values()) {
  252. result.add(node);
  253. }
  254. return result;
  255. }
  256. /**
  257. * 逐级追加设置节点的值(单个值)
  258. * @param leaf
  259. * @param map
  260. */
  261. public static void setValuesToParentNode(Map<Long,Object> leaf,Map<Long, TreeNode> map){
  262. Map<Long,Object> newLeaf=new HashMap<Long,Object>();
  263. // 设置每个节点的值
  264. for (Long id_: leaf.keySet()) {
  265. setParentNodeValue(newLeaf,map,id_);
  266. }
  267. if(newLeaf.size()>1){
  268. setValuesToParentNode(newLeaf, map);
  269. }
  270. }
  271. /**
  272. * 逐级追加设置节点的值(多个值)
  273. * @param leaf
  274. * @param map
  275. */
  276. public static void setMultiValuesToParentNode( Map<Long,Object> leaf,Map<Long, TreeNode> map){
  277. Map<Long,Object> newLeaf=new HashMap<Long,Object>();
  278. // 设置每个节点的值
  279. for (Long id_: leaf.keySet()) {
  280. setParentNodeMultiValues(newLeaf,map,id_);
  281. }
  282. if(newLeaf.size()>1){
  283. setMultiValuesToParentNode(newLeaf, map);
  284. }
  285. }
  286. /**
  287. * 数学运算
  288. * @param mathChar
  289. * @param dest
  290. * @param newValue
  291. */
  292. public static void mathHandle(String mathChar,double dest,double newValue){
  293. switch (mathChar) {
  294. case "+":
  295. dest+=newValue;
  296. break;
  297. case "-":
  298. dest-=newValue;
  299. break;
  300. case "*":
  301. dest*=newValue;
  302. break;
  303. case "/":
  304. dest/=newValue;
  305. break;
  306. default:
  307. break;
  308. }
  309. }
  310. /**
  311. * 查找最小子叶节点(没有子节点的节点)
  312. * @param node
  313. * @param leafList
  314. */
  315. private static void findMinNodes(TreeNode node,Map<Long,Object> leafList){
  316. if(node.getChildren().size()>0){
  317. TreeNode nodeTmp=null;
  318. for (int i = 0; i < node.getChildren().size(); i++) {
  319. nodeTmp= node.getChildren().get(i);
  320. findMinNodes(nodeTmp,leafList);
  321. }
  322. }else{
  323. leafList.put(node.getId(),node.getId());
  324. }
  325. }
  326. /**
  327. * 根据ID逐级查找父节点并设置值(设置单个值逐级递归)
  328. * @param map
  329. * @param id
  330. */
  331. private static void setParentNodeValue(Map<Long,Object> newLeaf,Map<Long, TreeNode> map,long id){
  332. TreeNode node=map.get(id);
  333. // 设置自身节点的值
  334. if(!node.isAddSelf()){
  335. node.setAddSelf(true);
  336. node.getValues().add(node.getValue());
  337. // 更新节点数据
  338. map.put(node.getId(),node);
  339. }
  340. TreeNode pNode=map.get(node.getPid());
  341. if(pNode!=null){
  342. // 将子节点的值赋给父节点
  343. pNode.getValues().addAll(node.getValues());
  344. // 设置自身节点的值
  345. if(!pNode.isAddSelf()){
  346. pNode.setAddSelf(true);
  347. pNode.getValues().add(pNode.getValue());
  348. }
  349. // 更新节点数据
  350. map.put(pNode.getId(),pNode);
  351. //setParentNodeValue(map,pNode.getId());
  352. newLeaf.put(pNode.getId(), pNode.getId());
  353. }
  354. }
  355. /**
  356. * 根据ID逐级查找父节点并设置值(设置多个值逐级递归)
  357. * @param map
  358. * @param id
  359. */
  360. private static void setParentNodeMultiValues(Map<Long,Object> newLeaf,Map<Long, TreeNode> map,long id){
  361. TreeNode node=map.get(id);
  362. // 设置自身节点的值
  363. if(!node.isAddSelf()){
  364. node.setAddSelf(true);
  365. node.getChildrenMultiValues().add(node.getMultiValues());
  366. // 更新节点数据
  367. map.put(node.getId(),node);
  368. }
  369. TreeNode pNode=map.get(node.getPid());
  370. if(pNode!=null){
  371. // 将子节点的值赋给父节点
  372. pNode.getChildrenMultiValues().addAll(node.getChildrenMultiValues());
  373. // 设置自身节点的值
  374. if(!pNode.isAddSelf()){
  375. pNode.setAddSelf(true);
  376. pNode.getChildrenMultiValues().add(pNode.getMultiValues());
  377. }
  378. // 更新节点数据
  379. map.put(pNode.getId(),pNode);
  380. //setParentNodeMultiValues(map,pNode.getId());
  381. newLeaf.put(pNode.getId(), pNode.getId());
  382. }
  383. }
  384. @SuppressWarnings("unused")
  385. public static void main(String[] args) {
  386. TreeNode tree=new TreeNode();
  387. tree.setId(1);
  388. tree.setLabel("顶层节点");
  389. tree.setValue(1);
  390. tree.setChildrenMultiValues(new ArrayList<double []>());
  391. tree.setPid(0);
  392. List<TreeNode> list =new ArrayList<TreeNode>();
  393. TreeNode node1=new TreeNode();
  394. node1.setId(2);
  395. node1.setLabel("子节点1");
  396. node1.setValue(100);
  397. node1.setMultiValues(new double[]{5,7,3});
  398. node1.setChildrenMultiValues(new ArrayList<double []>());
  399. node1.setPid(1);
  400. list.add(node1);
  401. TreeNode node2=new TreeNode();
  402. node2.setId(3);
  403. node2.setLabel("子节点2");
  404. node2.setValue(10);
  405. node2.setMultiValues(new double[]{2,5,8});
  406. node2.setChildrenMultiValues(new ArrayList<double []>());
  407. node2.setPid(1);
  408. list.add(node2);
  409. tree.setChildren(list);
  410. List<TreeNode> destList=new ArrayList<TreeNode>();
  411. TreeManager.treeToList(tree,destList);
  412. System.out.println("tree转list完成");
  413. List<TreeNode> treeList=TreeManager.listToTree(destList,1);
  414. System.out.println("List转tree完成");
  415. /*******************注意单个值计算结果会影响多个值计算结果**************/
  416. List<TreeNode> treeListSingleValue=TreeManager.listToTreeWithSingleValue(destList,1);
  417. System.out.println("List转tree 汇总唯一值value完成");
  418. List<TreeNode> treeListSingleValue2=TreeManager.treeToListWithSingleValue(tree);
  419. System.out.println("tree转List 汇总唯一值value完成");
  420. // List<TreeNode> treeListMultiValues=TreeManager.listToTreeWithMultiValues(destList,1,3);
  421. // System.out.println("List转tree 汇总多个值values完成");
  422. //
  423. // List<TreeNode> treeListMultiValues2=TreeManager.treeToListWithMultiValues(tree,3);
  424. // System.out.println("tree转List 汇总多个值values完成");
  425. }
  426. }

注:如果数据字段跟工具树的不一致可以使用Map转对象来实现。

Github源码:https://github.com/open-micro-services/springcloud/tree/master/sc-demo-projects/sb-tree

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/171042
推荐阅读
相关标签
  

闽ICP备14008679号