【java解决List对象转为树结构速度慢的问题】

项目场景:

行政区划树结构数据共3989条数据,java使用递归为树结构用时10s以上,优化树结构的实现。


问题解决:

行政区划树结构数据共3989条数据,java使用递归为树结构用时10s以上,优化树结构的实现。搜索资料,找到三种形式生成树结构的方法,进行用时测试。
参考博客链接:https://blog.csdn.net/qq_46258463/article/details/130562711
工具类代码分享:

package com.mxpt.system.util;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @author :lcq
 * @Date : 2023/5/8 9:52
 */

/**
 * 使用前提:
 *  主要是根据 反射来 组装树形,所以 要保证 存在下面三个基本属性 regionId,parentId,children
 */
public class TreeUtil {

    /**
     * 1.通过递归方式构建树
     *
     * @param list 列表
     * @return {@link List}<{@link T}>
     */
    public static <T> List<T> buildTreeByRecursion(List<T> list) {
        return buildTreeByRecursion(list, "regionId", "parentId", "children");
    }

    /**
     * 2.通过Map方式构建树
     *
     * @param list 列表
     * @return {@link List}<{@link T}>
     */
    public static <T> List<T> buildTreeByMap(List<T> list) {
        return buildTreeByMap(list, "regionId", "parentId", "children", "0");
    }

    /**
     * 3.通过两层for循环方式构建树
     *
     * @param list 列表
     * @return {@link List}<{@link T}>
     */
    public static <T> List<T> buildTreeByTwoLayersFor(List<T> list) {
        return buildTreeByTwoLayersFor(list, "regionId", "parentId", "children", "0");
    }

    /**
     * 通过递归方式构建树
     *
     * @param list         列表
     * @param idName       id名称
     * @param parentIdName 父id名称
     * @param childrenName 子节点列表名称
     * @return {@link List}<{@link T}>
     */
    public static <T> List<T> buildTreeByRecursion(List<T> list, String idName, String parentIdName, String childrenName) {
        if (StringUtils.isBlank(idName) || StringUtils.isBlank(parentIdName) || StringUtils.isBlank(childrenName)) {
            return new ArrayList<>();
        }
        List<T> returnList = new ArrayList<>();
        //获取list中所有的主键id
        List<String> ids = list.stream().map(o -> getFieldValue(o, idName).toString()).collect(Collectors.toList());

        for (T t : list) {
            String parentId = getFieldValue(t, parentIdName).toString();
            //如果是顶级节点, 遍历该父节点的所有子节点,因为顶层的parentId为0
            if (!ids.contains(parentId)) {
                buildTreeRecursive(list, t, idName, parentIdName, childrenName);
                returnList.add(t);
            }
        }
        if (returnList.isEmpty()) {
            returnList = list;
        }
        return returnList;
    }

    /**
     * 递归fn
     *
     * @param list 分类表
     * @param node 子节点
     */
    private static <T> void buildTreeRecursive(List<T> list, T node, String idName, String parentIdName, String childrenName) {
        // 得到子节点列表
        List<T> childList = getChildList(list, node, idName, parentIdName);
        setFieldValue(node, childList, childrenName);
        for (T child : childList) {
            if (hasChild(list, child, idName, parentIdName)) {
                buildTreeRecursive(list, child, idName, parentIdName, childrenName);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private static <T> List<T> getChildList(List<T> list, T node, String idName, String parentIdName) {
        List<T> tlist = new ArrayList<>();
        String oId = getFieldValue(node, idName).toString();
        for (T child : list) {
            String tParentId = getFieldValue(child, parentIdName).toString();
            if (tParentId.equals(oId)) {
                tlist.add(child);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private static <T> boolean hasChild(List<T> list, T t, String idName, String parentIdName) {
        return getChildList(list, t, idName, parentIdName).size() > 0;
    }

    /**
     * 通过Map方式构建树
     *
     * @param list           列表
     * @param idName         id名称
     * @param parentIdName   父id名称
     * @param childrenName   子节点列表名称
     * @param topParentIdVal 顶层节点父id的值
     * @return {@link List}<{@link T}>
     */
    public static <T> List<T> buildTreeByMap(List<T> list, String idName, String parentIdName, String childrenName, String topParentIdVal) {
        if (StringUtils.isBlank(idName) || StringUtils.isBlank(parentIdName) || StringUtils.isBlank(childrenName)) {
            return new ArrayList<>();
        }
        //根据parentId进行分组
        Map<String, List<T>> mapList = list.stream().collect(Collectors.groupingBy(o -> getFieldValue(o, parentIdName).toString()));
        //给每个节点设置子节点列表
        list.forEach(node -> setFieldValue(node, mapList.get(getFieldValue(node, idName).toString()), childrenName));
        return list.stream().filter(o -> topParentIdVal.equals(getFieldValue(o, parentIdName).toString())).collect(Collectors.toList());
    }

    /**
     * 获取属性值
     *
     * @param o         对象
     * @param fieldName 属性名
     * @return {@link String}
     */
    private static Object getFieldValue(Object o, String fieldName) {
        try {
            Class<?> oClass = o.getClass();
            Field field = oClass.getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(o);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 设置字段值
     *
     * @param o         对象
     * @param val       值
     * @param fieldName 属性名
     */
    private static void setFieldValue(Object o, Object val, String fieldName) {
        try {
            Class<?> oClass = o.getClass();
            Field field = oClass.getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(o, val);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过两层for循环方式构建树
     *
     * @param list           列表
     * @param idName         id名称
     * @param parentIdName   父id名称
     * @param childrenName   子节点列表名称
     * @param topParentIdVal 顶层节点父id的值
     * @return {@link List}<{@link T}>
     */
    public static <T> List<T> buildTreeByTwoLayersFor(List<T> list, String idName, String parentIdName, String childrenName, String topParentIdVal) {
        List<T> resultList = new ArrayList<>();
        for (T node : list) {
            //如果是顶层节点
            if (topParentIdVal.equals(getFieldValue(node, parentIdName).toString())) {
                resultList.add(node);
            }
            for (T child : list) {
                if (getFieldValue(child, parentIdName).equals(getFieldValue(node, idName))) {
                    List<T> childrenList = (List<T>) getFieldValue(node, childrenName);
                    if (CollectionUtils.isEmpty(childrenList)) {
                        childrenList = new ArrayList<>();
                        setFieldValue(node, childrenList, childrenName);
                    }
                    childrenList.add(child);
                }
            }
        }
        return resultList;
    }

}




工具类的调用:

工具类代码调用:
最终测试得到,针对我的数据,方法2通过Map方式构建树的效率最高,实现2秒内返回。

    @Override
    public List<SysRegion> selectSysRegionTreeDataList(SysRegion sysRegion)
    {
        long startTime0 = System.currentTimeMillis();
        List<SysRegion> sysRegions = sysRegionMapper.selectSysRegionListWithBound(sysRegion);
        long endTime0 = System.currentTimeMillis();
        System.out.println("查询时间:"+(endTime0-startTime0)+"ms");

//        //执行时间统计
//        long startTime = System.currentTimeMillis();
//        //方法1:通过递归方式构建树
//        List<SysRegion> list1 = TreeUtil.buildTreeByRecursion(sysRegions);
//        //执行时间统计
        long endTime = System.currentTimeMillis();
//        System.out.println("方法1递归方式构建树--执行时间:" + (endTime-startTime)/1000 + "s");

        //方法2:通过Map方式构建树
        List<SysRegion> list2 = TreeUtil.buildTreeByMap(sysRegions, "regionId", "parentId", "children", "0");
        //执行时间统计
        long endTime2 = System.currentTimeMillis();
        System.out.println("方法2Map方式构建树--执行时间:" + (endTime2-endTime)/1000 + "s");

//        //方法3:通过两层for循环方式构建树
//        List<SysRegion> list3 = TreeUtil.buildTreeByTwoLayersFor(sysRegions);
//        //执行时间统计
//        long endTime3 = System.currentTimeMillis();
//        System.out.println("方法3两层for循环方式构建树--执行时间:"+ (endTime3-endTime2)/1000 + "s");

        return list2;
    }

  • 14
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您可以使用递归算法将List年级、班级和课程数据转换为树形结构。以下是一个示例代码: ```java import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; class TreeNode { private String name; private List<TreeNode> children; public TreeNode(String name) { this.name = name; this.children = new ArrayList<>(); } public String getName() { return name; } public List<TreeNode> getChildren() { return children; } public void addChild(TreeNode child) { children.add(child); } } public class Main { public static void main(String[] args) { // 生成样例数据 Map<String, List<String>> gradeData = new HashMap<>(); gradeData.put("Grade 1", List.of("Class A", "Class B")); gradeData.put("Grade 2", List.of("Class C", "Class D")); gradeData.put("Grade 3", List.of("Class E")); Map<String, List<String>> classData = new HashMap<>(); classData.put("Class A", List.of("Math", "Science")); classData.put("Class B", List.of("English")); classData.put("Class C", List.of("History", "Geography")); classData.put("Class D", List.of("Physics", "Chemistry")); classData.put("Class E", List.of("Art")); // 转换为树形结构 TreeNode root = new TreeNode("School"); for (String grade : gradeData.keySet()) { TreeNode gradeNode = new TreeNode(grade); root.addChild(gradeNode); List<String> classes = gradeData.get(grade); for (String className : classes) { TreeNode classNode = new TreeNode(className); gradeNode.addChild(classNode); List<String> courses = classData.get(className); for (String course : courses) { TreeNode courseNode = new TreeNode(course); classNode.addChild(courseNode); } } } // 打印树形结构 printTree(root, 0); } private static void printTree(TreeNode node, int depth) { StringBuilder indent = new StringBuilder(); for (int i = 0; i < depth; i++) { indent.append(" "); } System.out.println(indent + node.getName()); for (TreeNode child : node.getChildren()) { printTree(child, depth + 1); } } } ``` 以上示例代码将List年级、班级和课程数据转换为一个树形结构,并打印出来。您可以根据实际情况修改数据结构和打印方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

haokan_Jia

你的鼓励就是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值