• java后端操作树结构


    一、树结构的三种组装方式(递归.双层for循环,map)

    (1)递归
    普通递归方法

     public Result getBmsMenuList(UserSessionVO userSessionInfo) {
            // 查询顶级节点菜单
            List<BmsMenuVO> bmsMenuVOList = bmsMenuDao.selectBmsMenuList(new BmsMenuQueryConditionVO());
    
            for (BmsMenuVO bmsMenuVO : bmsMenuVOList) {
                getBmsMenuListByRecursion(bmsMenuVO);
            }
    
            return Result.createWithModels(null, bmsMenuVOList);
        }
    
     private void getBmsMenuListByRecursion(BmsMenuVO bmsMenuVO) {
            List<BmsMenuVO> bmsMenuVOS = bmsMenuDao.selectBmsMenuList(new BmsMenuQueryConditionVO().setParentId(bmsMenuVO.getId()));
            if (CollectionUtils.isEmpty(bmsMenuVOS)) {
                return;
            }
            bmsMenuVO.setChildBmsMenuList(bmsMenuVOS);
            for (BmsMenuVO menuVO : bmsMenuVOS) {
                getBmsMenuListByRecursion(menuVO);
            }
    }
    

    stream流递归方法

    //获取父节点
    List collect = trees.stream().filter(m -> m.getParentId() == 0).map(
        (m) -> {
            m.setChildren(getChildrenList(m, trees));
            return m;
        }
    ).collect(Collectors.toList());
     
        /**
         * 获取子节点列表
         * @param tree
         * @param list
         * @return
         */
        public static List getChildrenList(TreeSelect tree, List list){
            List children = list.stream().filter(item -> Objects.equals(item.getParentId(), tree.getId())).map(
                    (item) -> {
                        item.setChildren(getChildrenList(item, list));
                        return item;
                    }
            ).collect(Collectors.toList());
            return children;
        }
    

    (2)双层for循环

    // 查询主节点
    List bmsMenuVOList = bmsRoleMenuDao.getAllRoleMenuList(condition);
    
    // 拼装结果
     List bmsMenuTree = new ArrayList<>();
     for (BmsMenuVO bmsMenuVO : bmsMenuVOList) {
          // 根节点的父Id为null
          if (bmsMenuVO.getParentId() == null) {
                    bmsMenuTree.add(bmsMenuVO);
          }
          for (BmsMenuVO menuVO : bmsMenuVOList) {
               if (menuVO.getParentId() != null && menuVO.getParentId().equals(bmsMenuVO.getId())) {
                   if (CollectionUtils.isEmpty(bmsMenuVO.getChildBmsMenuList())) {
                            bmsMenuVO.setChildBmsMenuList(new ArrayList<>());
                    }
                    bmsMenuVO.getChildBmsMenuList().add(menuVO);
               }
           }
      }
    
      // 返回结果
     return Result.createWithModels(null, bmsMenuTree);
    

    (3)map遍历

     // 查询所有节点
     List bmsMenuVOList = bmsRoleMenuDao.getAllRoleMenuList(condition);
           
     // 拼装结果     
     List bmsMenuTree = new ArrayList<>();
     // 用来存储节点的子元素map
     Map childBmsMenuMap = new LinkedHashMap<>();
            for (BmsMenuVO menuVO : bmsMenuVOList) {
                childBmsMenuMap.put(menuVO.getId(), menuVO);
            }
            for (Long bmsMenuId : childBmsMenuMap.keySet()) {
                BmsMenuVO menuVO = childBmsMenuMap.get(bmsMenuId);
                Long parentId = menuVO.getParentId();
                if (parentId == null) {
                    bmsMenuTree.add(menuVO);
                } else {
                    BmsMenuVO parentMenuVO = childBmsMenuMap.get(parentId);
                    if (parentMenuVO.getChildBmsMenuList() == null) {
                        parentMenuVO.setChildBmsMenuList(new ArrayList<>());
                    }
                    parentMenuVO.getChildBmsMenuList().add(menuVO);
              }
    } 
    

    2、使用递归查询某个节点所在的树结构

    使用场景:当我们得到一个树形结构数据时,可能需要在树形结构上对数据进行筛选,例如通过文件夹(文件)名称模糊查询相关的文件夹并展现其父级。

    缺点:需要查询出完整的树形结构才能用作筛选,在数据量非常庞大的时候并不适用。

    @Data
    public class TreeDto {
    
       private String id;
       private String name;
       private List<TreeDto> subsetTreeDtoList;
    
    
    
       public TreeDto(String id,String name,List<TreeDto> subsetTreeDtoList){
           this.id = id;
           this.name = name;
           this.subsetTreeDtoList = subsetTreeDtoList;
       }
    }
    

    筛选

      /**
        * 树形筛选查找
        * @param treeDtoList 树形集合
        * @param idList 筛选条件(可以是其他条件)
        * @return 包含的节点数据
        */
       public static List screenTree(List treeDtoList, List idList){
           //最后返回的筛选完成的集合
           List screeningOfCompleteList = new ArrayList<>();
           if (listIsNotEmpty(treeDtoList) && listIsNotEmpty(idList)){
               for (TreeDto treeDto : treeDtoList){
                   List subsetList = treeDto.getSubsetTreeDtoList();
                   //递归筛选完成后的返回的需要添加的数据
                   TreeDto addTreeDto = getSubsetPmsPlanPo(treeDto,subsetList,idList);
                   if (isNotEmpty(addTreeDto)){
                       screeningOfCompleteList.add(addTreeDto);
                   }
               }
               return screeningOfCompleteList;
           }
           return null;
       }
    
    
       /**
        * 筛选符合的集合并返回
        * @param treeDto 树形类
        * @param subsetTreeDtoList 子集集合
        * @param idList 筛选条件
        * @return 筛选成功的类
        */
       public static TreeDto getSubsetPmsPlanPo(TreeDto treeDto,List subsetTreeDtoList,List idList){
           //作为筛选条件的判断值
           String id = treeDto.getId();
           //有子集时继续向下寻找
           if (listIsNotEmpty(subsetTreeDtoList)){
               List addTreeDtoList = new ArrayList<>();
               for (TreeDto subsetTreeDto : subsetTreeDtoList){
                   List subsetList = subsetTreeDto.getSubsetTreeDtoList();
                   TreeDto newTreeDto = getSubsetPmsPlanPo(subsetTreeDto,subsetList,idList);
                   //当子集筛选完不为空时添加
                   if (isNotEmpty(newTreeDto)){
                       addTreeDtoList.add(newTreeDto);
                   }
               }
               //子集满足条件筛选时集合不为空时,替换对象集合内容并返回当前对象
               if (listIsNotEmpty(addTreeDtoList)){
                   treeDto.setSubsetTreeDtoList(addTreeDtoList);
                   return treeDto;
                   //当前对象子集对象不满足条件时,判断当前对象自己是否满足筛选条件,满足设置子集集合为空,并返回当前对象
               }else if (listIsEmpty(addTreeDtoList) && idList.contains(id)){
                   treeDto.setSubsetTreeDtoList(null);
                   return treeDto;
               }else {
                   //未满足筛选条件直接返回null
                   return null;
               }
           }else {
               //无子集时判断当前对象是否满足筛选条件
               if (idList.contains(id)){
                   return treeDto;
               }else {
                   return null;
               }
           }
       }
    
       /**
        * 判断集合为空
        * @param list 需要判断的集合
        * @return 集合为空时返回 true
        */
       public static boolean listIsEmpty(Collection list){
           return  (null == list || list.size() == 0);
       }
    
       /**
        * 判断集合非空
        * @param list 需要判断的集合
        * @return 集合非空时返回 true
        */
       public static boolean listIsNotEmpty(Collection list){
           return !listIsEmpty(list);
       }
    
       /**
        * 判断对象为null或空时
        * @param object 对象
        * @return 对象为空或null时返回 true
        */
       public static boolean isEmpty(Object object) {
           if (object == null) {
               return (true);
           }
           if ("".equals(object)) {
               return (true);
           }
           if ("null".equals(object)) {
               return (true);
           }
           return (false);
       }
    
       /**
        * 判断对象非空
        * @param object 对象
        * @return 对象为非空时返回 true
        */
       public static boolean isNotEmpty(Object object) {
           if (object != null && !object.equals("") && !object.equals("null")) {
               return (true);
           }
           return (false);
       }
    
       public static void main(String[] args) {
           TreeDto treeDto1 = new TreeDto("1","A",new ArrayList());
           TreeDto treeDto1_1 = new TreeDto("1.1","A-A",new ArrayList());
           TreeDto treeDto1_2 = new TreeDto("1.2","A-B",new ArrayList());
           TreeDto treeDto1_3 = new TreeDto("1.3","A-C",new ArrayList());
           treeDto1.getSubsetTreeDtoList().add(treeDto1_1);
           treeDto1.getSubsetTreeDtoList().add(treeDto1_2);
           treeDto1.getSubsetTreeDtoList().add(treeDto1_3);
    
           TreeDto treeDto2 = new TreeDto("2","B",new ArrayList());
           TreeDto treeDto2_1 = new TreeDto("2.1","B-A",new ArrayList());
           TreeDto treeDto2_2 = new TreeDto("2.2","B-B",new ArrayList());
           TreeDto treeDto2_3 = new TreeDto("2.3","B-C",new ArrayList());
           TreeDto treeDto2_3_1 = new TreeDto("2.3.1","B-C-A",null);
           treeDto2.getSubsetTreeDtoList().add(treeDto2_1);
           treeDto2.getSubsetTreeDtoList().add(treeDto2_2);
           treeDto2.getSubsetTreeDtoList().add(treeDto2_3);
           treeDto2.getSubsetTreeDtoList().get(2).getSubsetTreeDtoList().add(treeDto2_3_1);
    
           String[] array = {"1.3","2.2","2.3.1"};
           List idList = Arrays.asList(array);
           List treeDtoList = new ArrayList<>();
           treeDtoList.add(treeDto1);
           treeDtoList.add(treeDto2);
           System.out.println(JSON.toJSONString(screenTree(treeDtoList,idList)));
       }
    }
    

    返回结果为
    image

  • 相关阅读:
    批量删除docker过期停止的容器(全)
    Java 在Word文档中添加艺术字
    MySQL覆盖索引的使用
    如何对 TiDB 进行 TPC-C 测试
    面试官:说说JVM内存整体结构?
    Cpp浅析系列-STL之map
    开源任务调度框架
    《悉达多》
    ACM MM 2022 Oral | PRVR: 新的文本到视频跨模态检索子任务
    全国科技者工作日—为创新和未来而努力
  • 原文地址:https://www.cnblogs.com/cgy1995/p/17782289.html