一、《放肆》如约而至
今早5:00在迷迷糊糊中醒来,打开手机一看,许嵩又发新歌了,名字叫做《放肆》,澎湃的旋律,依旧古典高雅的用词,这个大男孩,已经不像12年那时候发些伤感非主流的歌曲了,86年出生的他,除了依旧留着亘古不变的长刘海发型,心理俨然住进了一个老灵魂。
再小酣一会儿,6:40闹铃响起,穿衣洗刷梳头,便匆匆忙忙的骑着小单车,赶去了地铁站,重复着之前每天的境况。地铁站人挤人,稀薄的空气被每个人尽力吮吸着,每个人在微不足道的间隙里腾出手来,拿着手机忙活着自己的事,人与人的物理距离看起来很近,但每个人仿佛都被丢进了一个叫做屏幕世界的地方,心理距离远的不着边际。我望着一个个陌生的面孔,放弃了看电子书的想法,带上了耳机微闭双眼,开始循环播放起了音乐,虽然年纪大了,但口味依旧还是许嵩,汪苏泷,薛之谦,毛不易等人的歌曲,俩字:好听。
有时我就在想,每天重复着差不多的日子究竟有什么意义,我会不会也变成那种25岁就死了,只是75岁才埋的人生,但,这不是我想要的人生。听着汪苏泷翻唱的《我们》,我想到了一句很煽情很非主流的话:这么些年我用泡沫堆砌起来的感情,虽然时常修缮小心呵护,可是风一吹,还是散了。
。。。。。。
来到公司,打卡,开电脑,简单的吃个早饭,心想着今天做点什么或写点什么,10月份已然过去了三分之一还多,可是自己还没构思好要去写点什么,无聊的翻看着自己随意写的一些代码,麻木的点击着公司项目上的功能,我看到了一棵树,好吧,还真是一棵树,会分叉还会横着长的一棵树,想了想,好久没有专注于代码本身了,那就写点实现某项功能的小例子,比如:使用递归结合Lambda表达式去实现这棵树。在这里,我想提供一个类似于思想模板的代码,基本使用它都能够轻松完成后台的树结构数据的实现,言归正传,开始吧。
1.问题来源
先看一张图:
我们做的这块是一个关于信票的功能,大体是一张信票我签发给你,你再签发给别人,别人再签发给另一批人,另一批人也对外签发,只要手持信票余额足够,是可以签发给多人的,并且也是有可能A->B,B->C,C->A,至于具体的业务我就不做多描述(泄露不好不好),总得来说,我们需要用用一张图来描绘出这种层级关系,明显这是一种典型的树状结构(由于我们的每条数据有自己代号,所以刚刚我举的ACBA并不会形成一个闭环,那两个A所代表的层级也是不同的),这时候需要我们处理成树状架构的数据组给前台了。我展示的这张图层级只到了2,而且还没展示很复杂的结构(造条数据很麻烦的,原谅我的懒惰),但大体意思应该能看明白。
一看,有觉悟的后台同志们就明白了要用递归完成数据处理,我微微一笑,没错,肯定要用递归,然并软,我的内心早已波涛汹涌:我的递归玩的是真不溜,工作到现在,还真没正儿八经的用过递归思维。不过我不用太过担心,毕竟最初始的这个任务不是落我头上,不过这块的业务我也参与了不少,所以我也得想想。同事去研究了,因为我们的这个数据不是直来直去的那种,并不是在表中存了父子id可以直接关联取数据,所以处理起来也没那么容易,后来差不多同事忙活了不少时间,写了一套代码,可能数据量一多的时候,貌似还会出问题,这就不是我关心的了。然而,后来我写的一块功能也用到了这个图,这就关我事,参考了下网上处理这种问题的代码,我做了下处理和变形,完美契合,虽然代码多了点,但屡试不爽,下面是我处理后的代码:
package cn.exrick.xboot.modules.bill.entity; import com.alibaba.fastjson.JSON; import java.util.*; /** * zae */ public class BillNodeTree { public static Map getTreeList(List<BillCirculation> billCirculationList) { // 读取层次数据结果集列表 List dataList = VirtualDataGenerator.getVirtualResult(billCirculationList); if(dataList==null || dataList.size()==0){ return new HashMap(); } // 节点列表(散列表,用于临时存储节点对象) HashMap nodeList = new HashMap(); // 根节点 Node root = null; // 根据结果集构造节点列表(存入散列表) for (Iterator it = dataList.iterator(); it.hasNext();) { Map dataRecord = (Map) it.next(); Node node = new Node(); node.id = (String)dataRecord.get("id"); node.orgIssueUnitUnnoName = (String) dataRecord.get("orgIssueUnitUnnoName"); node.level = Integer.parseInt(dataRecord.get("level")+""); node.parentId = (String)dataRecord.get("parentId"); nodeList.put(node.id, node); } // 构造无序的多叉树 Set entrySet = nodeList.entrySet(); for (Iterator it = entrySet.iterator(); it.hasNext();) { Node node = (Node) ((Map.Entry) it.next()).getValue(); if (node.parentId == null || node.parentId.equals("") || "null".equals(node.parentId)) { root = node; } else { ((Node) nodeList.get(node.parentId)).addChild(node); } } // 输出无序的树形菜单的JSON字符串 // System.out.println(root.toString()); // 对多叉树进行横向排序 // root.sortChildren(); // 输出有序的树形菜单的JSON字符串 Map operatorMaps = (Map) JSON.parseObject(root.toString(),Map.class); return operatorMaps; } } /** * 节点类 */ class Node { /** * 节点编号 */ public String id; /** * 节点内容 */ public String orgIssueUnitUnnoName; /** * 级别 */ public Integer level; /** * 父节点编号 */ public String parentId; /** * 孩子节点列表 */ private Children children = new Children(); // 先序遍历,拼接JSON字符串 public String toString() { String result = "{" + "id : '" + id + "'" + ", orgIssueUnitUnnoName : '" + orgIssueUnitUnnoName + "'" + ", level : " + level + ""; if (children != null && children.getSize() != 0) { result += ", children : " + children.toString(); } else { result += ", expand : false"; } return result + "}"; } // 兄弟节点横向排序 public void sortChildren() { if (children != null && children.getSize() != 0) { children.sortChildren(); } } // 添加孩子节点 public void addChild(Node node) { this.children.addChild(node); } } /** * @author zangchuanlei * 孩子列表类 */ class Children { private List list = new ArrayList(); public int getSize() { return list.size(); } public void addChild(Node node) { list.add(node); } // 拼接孩子节点的JSON字符串 public String toString() { String result = "["; for (Iterator it = list.iterator(); it.hasNext();) { result += ((Node) it.next()).toString(); result += ","; } result = result.substring(0, result.length() - 1); result += "]"; return result; } // 孩子节点排序 public void sortChildren() { // 对本层节点进行排序 // 可根据不同的排序属性,传入不同的比较器,这里传入ID比较器 Collections.sort(list, new NodeIDComparator()); // 对每个节点的下一层节点进行排序 for (Iterator it = list.iterator(); it.hasNext();) { ((Node) it.next()).sortChildren(); } } } /** * @author zangchuanlei * 节点比较器 */ class NodeIDComparator implements Comparator { // 按照节点编号比较 public int compare(Object o1, Object o2) { int j1 = Integer.parseInt(((Node)o1).id); int j2 = Integer.parseInt(((Node)o2).id); return (j1 < j2 ? -1 : (j1 == j2 ? 0 : 1)); } } /** * @author zangchuanlei * 构造虚拟的层次数据 */ class VirtualDataGenerator { // 构造无序的结果集列表,实际应用中,该数据应该从数据库中查询获得; public static List getVirtualResult(List<BillCirculation> billCirculationList) { List dataList = new ArrayList(); for(BillCirculation billCirculation:billCirculationList){ HashMap dataRecord1 = new HashMap(); dataRecord1.put("id", billCirculation.getId()); dataRecord1.put("orgIssueUnitUnnoName",billCirculation.getCorpName()); dataRecord1.put("level",billCirculation.getLevel()); if(billCirculation.getLevel() == 1){ dataRecord1.put("parentId", ""); }else{ String parentId = null; for(BillCirculation billCirculation1:billCirculationList){ if(billCirculation.getIssueUnitUnno().equals(billCirculation1.getSignInUnitUnno()) && billCirculation1.getLevel() == billCirculation.getLevel()-1){ parentId = billCirculation1.getId(); } } dataRecord1.put("parentId",parentId); } dataList.add(dataRecord1); } return dataList; } }