树工具类TreeUtils

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);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值