package com.nuzar.cloud.common.utils;
import com.nuzar.cloud.common.functions.SetFunction;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 树形结构工具类
*
* @author MadMax
* @date 2021/9/1 9:07
*/
public class TreeUtils {
/**
* 将List清单 进行属性结构 转换 实体中需要有 SonList 和 ParentId字段
*
* @param originList
* @param <T>
* @return
*/
public static <T> List<T> getTreeList(List<T> originList,
Class<T> clazz,
Function<T, Object> fnKey,
Function<T, Object> fnParentKey,
Function<T, List<T>> fnSonListGet,
SetFunction<T, List<T>> fnSonListSet) {
if (originList == null || originList.size() == 0) {
return originList;
}
List<T> list = originList;
// 创建匿名类
List<T> tree = new ArrayList<T>() {
};
T parent = createInstance(clazz);
if (list != null) {
// make a tree
fnSonListSet.apply(parent, tree);
findSon(parent, list, fnKey, fnParentKey, fnSonListGet, fnSonListSet);
}
return fnSonListGet.apply(parent);
}
/**
* @param originTree 样板Tree
* @param originList 过滤出这些叶子
* @param clazz
* @param fnKey
* @param fnParentKey
* @param fnSonListGet
* @param fnSonListSet
* @param <T>
* @return
*/
public static <T> List<T> filterTreeList(
List<T> originTree,
List<T> originList,
Class<T> clazz,
Function<T, Object> fnKey,
Function<T, Object> fnParentKey,
Function<T, List<T>> fnSonListGet,
SetFunction<T, List<T>> fnSonListSet) {
if (originList == null || originList.size() == 0 || originTree == null || originTree.size() == 0) {
return originList;
}
List<T> parents = new ArrayList<>();
originList.forEach(t -> {
parents.addAll(findParents(originTree, t, fnKey, fnSonListGet));
});
// 清楚原来的son 重新组装
parents.forEach(t -> fnSonListSet.apply(t, null));
List<T> afterList = parents.stream().distinct().collect(Collectors.toList());
return getTreeList(afterList, clazz, fnKey, fnParentKey, fnSonListGet, fnSonListSet);
}
/**
* 递归 制造树形结构
*
* @param menu
* @param list
*/
private static <T> void findSon(T menu, List<T> list,
Function<T, Object> fnKey,
Function<T, Object> fnParentKey,
Function<T, List<T>> fnSonListGet,
SetFunction<T, List<T>> fnSonListSet) {
if (list == null || list.size() == 0) {
return;
}
List<T> apps = list.stream().filter(t ->
(fnKey.apply(menu) == null && fnParentKey.apply(t) == null)
|| (fnKey.apply(menu) != null && fnKey.apply(menu).equals(fnParentKey.apply(t)))
).collect(Collectors.toList());
if (apps == null || apps.size() == 0) {
return;
}
fnSonListSet.apply(menu, apps);
list.remove(apps);
List<T> sonList = fnSonListGet.apply(menu);
if (sonList != null) {
for (T subMenu : sonList) {
findSon(subMenu, list, fnKey, fnParentKey, fnSonListGet, fnSonListSet);
}
}
}
/**
* 返回所有的父亲。
*
* @param originTree
* @param son
* @param <T>
*/
private static <T> List<T> findParents(List<T> originTree, T son,
Function<T, Object> fnKey,
Function<T, List<T>> fnSonListGet) {
List<T> parentList = new ArrayList<>();
for (T t : originTree) {
if (fnSonListGet.apply(t) != null && fnSonListGet.apply(t).size() > 0) {
List<T> t1Parent = findParents(fnSonListGet.apply(t), son, fnKey, fnSonListGet);
if (t1Parent.size() > 0) {
parentList.add(t);
parentList.addAll(t1Parent);
}
} else {
if (fnKey.apply(t).equals(fnKey.apply(son))) {
parentList.add(son);
}
}
}
return parentList;
}
/**
* 利用匿名类获取 具体新建instance
* 类型推导
*
* @param <T>
* @return
*/
private static <T> T createInstance(Class<T> clazz) {
try {
return clazz.newInstance();
} catch (Exception e) {
throw new NullPointerException();
}
}
public static void main(String[] args) {
Dept d1 = new Dept("1", null);
Dept d11 = new Dept("1.1", "1");
Dept d12 = new Dept("1.2", "1");
Dept d2 = new Dept("2", null);
Dept d3 = new Dept("3", null);
Dept d31 = new Dept("3.1", "3");
Dept d32 = new Dept("3.2", "3");
Dept d311 = new Dept("3.1.1", "3.1");
//
Dept d41 = new Dept("4.1", "4");
List<Dept> all = new ArrayList<>();
all.add(d1);
all.add(d11);
all.add(d12);
all.add(d2);
all.add(d3);
all.add(d31);
all.add(d32);
all.add(d311);
List<Dept> tree = TreeUtils.getTreeList(all, Dept.class, Dept::getId,
Dept::getParent, Dept::getDepts, Dept::setDepts);
System.out.println(tree);
List<Dept> newList = new ArrayList<>();
newList.add(d311);
newList.add(d32);
newList.add(d11);
newList.add(d41);
List<Dept> newTree = TreeUtils.filterTreeList(tree, newList, Dept.class, Dept::getId,
Dept::getParent, Dept::getDepts, Dept::setDepts);
System.out.println(newTree);
}
static class Dept {
String id;
String parent;
List<Dept> depts = new ArrayList<>();
public Dept() {
}
public Dept(String id, String parent) {
this.id = id;
this.parent = parent;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getParent() {
return parent;
}
public void setParent(String parent) {
this.parent = parent;
}
public List<Dept> getDepts() {
return depts;
}
public void setDepts(List<Dept> depts) {
this.depts = depts;
}
}
}
用法:
List<SysMenus> menus = getUserMenus(userId);
List<SysMenus> list = sysMenusService.getMenus(tenant, null, null);
List<SysMenus> sampleTree = TreeUtils.getTreeList(list, SysMenus.class, SysMenus::getId, SysMenus::getParentId, SysMenus::getSubMenus, SysMenus::setSubMenus);
List<SysMenus> result = TreeUtils.filterTreeList(sampleTree, menus, SysMenus.class, SysMenus::getId, SysMenus::getParentId, SysMenus::getSubMenus, SysMenus::setSubMenus);
return CollectionUtils.sortDeep(result, Comparators.integer(SysMenus::getPriority), SysMenus::getSubMenus);