树形结构数据封装(及拉平)的几种方法

java(for循环处理、递归处理、map处理)

public class DemoApplicationTests {

	/*for循环写法*/
   /**
    * @param args
    */
   public static void main(String[] args) {
       ArrayList<Node> nodes = new ArrayList<>();
       nodes.add(new Node(1, 0, "1"));
       nodes.add(new Node(2, 0, "2"));
       nodes.add(new Node(3, 0, "3"));

       nodes.add(new Node(4, 1, "1-1"));
       nodes.add(new Node(5, 4, "1-1-1"));
       nodes.add(new Node(6, 4, "1-1-2"));
       nodes.add(new Node(7, 6, "1-1-2-1"));

       nodes.add(new Node(8, 2, "2-1"));
       nodes.add(new Node(9, 2, "2-2"));

       nodes.add(new Node(10, 3, "3-1"));

       ArrayList<Node> nodeTree = new ArrayList<>();

       long start = System.currentTimeMillis();
       for (Node node1 : nodes) {
           if (node1.getPid() == 0) {
               nodeTree.add(node1);
           }
           for (Node node2 : nodes) {
               if (node1.getId().equals(node2.getPid())) {
                   node1.getChildren().add(node2);
               }
           }
       }

       System.out.println(JSON.toJSONString(nodeTree));
       System.out.println(System.currentTimeMillis()-start);

   }

	/*使用map写法(目前最好的方法)*/
   @Test
   public void testTree() {
       ArrayList<Node> nodes = new ArrayList<>();
       nodes.add(new Node(1, 0, "1"));
       nodes.add(new Node(2, 0, "2"));
       nodes.add(new Node(3, 0, "3"));

       nodes.add(new Node(4, 1, "1-1"));
       nodes.add(new Node(5, 4, "1-1-1"));
       nodes.add(new Node(6, 4, "1-1-2"));
       nodes.add(new Node(7, 6, "1-1-2-1"));

       nodes.add(new Node(8, 2, "2-1"));
       nodes.add(new Node(9, 2, "2-2"));

       nodes.add(new Node(10, 3, "3-1"));

       long start = System.currentTimeMillis();
       Map<Integer,Node> map= new HashMap<>();
       nodes.forEach(e->map.put(e.getId(),e));

       for (Node node1 : nodes) {
           Optional.ofNullable(map.get(node1.getPid())).ifPresent(p->{
               p.children.add(node1);
           });
       }

       List<Node> list = nodes.stream().filter(e -> Objects.equals(e.getPid(), 0)).collect(Collectors.toList());

       System.out.println(JSON.toJSONString(list));

       System.out.println(System.currentTimeMillis()-start);


   }

	/** 递归写法 **/
	@Test
    public void testTree2() throws JsonProcessingException {
        ArrayList<Node> nodes = new ArrayList<>();
        nodes.add(new Node(1, 0, "1"));
        nodes.add(new Node(2, 0, "2"));
        nodes.add(new Node(3, 0, "3"));

        nodes.add(new Node(4, 1, "1-1"));
        nodes.add(new Node(5, 4, "1-1-1"));
        nodes.add(new Node(6, 4, "1-1-2"));
        nodes.add(new Node(7, 6, "1-1-2-1"));

        nodes.add(new Node(8, 2, "2-1"));
        nodes.add(new Node(9, 2, "2-2"));

        nodes.add(new Node(10, 3, "3-1"));

        List<Node> reultList = nodes.stream().filter(node -> node.getPid() == 0).map(node -> {
            List<Node> children = findChildren(node, nodes);
            node.setChildren(children);
            return node;
        }).collect(Collectors.toList());

        System.out.println(new ObjectMapper().writeValueAsString(reultList));


    }

    private static List<Node>  findChildren(Node e, ArrayList<Node> nodes) {
        List<Node> children1 = nodes.stream().filter(node -> node.getPid() == e.getId()).map(node -> {
            List<Node> children2 = findChildren(node, nodes);
            node.setChildren(children2);
            return node;
        }).collect(Collectors.toList());
        return children1;
    }
}


class Node {
   private Integer id;
   private Integer pid;
   private String name;
   List<Node> children = new ArrayList<>();
}

js将扁平数据处理成树状结构

map处理

transformTozTreeFormat: function (sNodes) {
   var i, l;
   var r = [];
   var tmpMap = {};
   
   for (i = 0, l = sNodes.length; i < l; i++) {
     // 将sNodes的每个元素都放进map中,结构为:id -> sNode (注意没有s)
     tmpMap[sNodes[i].id] = sNodes[i];
   }
   
   for (i = 0, l = sNodes.length; i < l; i++) {
     // 从map中,取出当前节点sNode[i]的父节点
     var p = tmpMap[sNodes[i].pid];
     // 如果当前节点存在父节点(并且当前节点的id和pid不同),
     // 则将当前节点sNode[i]添加到父节点的children属性中(如果父节点的children属性还没有的话,就先给个空数组)
     if (p && sNodes[i].id != sNodes[i].pid) {
       var children = this.nodeChildren(p);
       if (!children) {
         children = this.nodeChildren(p, []);
       }
       children.push(sNodes[i]);
     } else {
      // 如果不存在父节点,则直接添加到结果集中
       r.push(sNodes[i]);
     }
   }
   // 所以循环了一遍之后,每一个节点如果能找到它的父节点,那么都会添加到父节点的children当中。
   //                  没有找到父节点的,都会添加到最后的结果集中。
   return r;
 }
nodeChildren: function (node, newChildren) {
   if (typeof newChildren !== 'undefined') {
     node.children = newChildren;
   }
   return node.children;
}


递归处理

  • 文件夹和文件的关系,文件夹存在嵌套,文件属于某一个文件夹
  • clonedeep是一个深拷贝的方法
// 这个就是首先遍历所有的文件夹,遍历到每一个文件夹的时候,再去遍历每一个文件,
// 因此就可以找到属于当前文件夹的文件,把这个文件添加到当前的这个文件夹中,
// 直到所有的文件夹遍历完成。这样,每个文件都会放到对应的文件夹中。
// 注意到,每一个文件只能属于一个文件夹,所以当一个文件已经找到了文件夹,就把这个文件给移除掉
export const putFileInFolder = (folderList, fileList) => {

  const folderListCloned = clonedeep(folderList)
  
  const fileListCloned = clonedeep(fileList)
  
  return folderListCloned.map(folderItem => {
  
    const folderId = folderItem.id
    
    let index = fileListCloned.length
    
    while (--index >= 0) {
    
      const fileItem = fileListCloned[index]
      
      if (fileItem.folder_id === folderId) {
        const file = fileListCloned.splice(index, 1)[0]
        file.title = file.name
        if (folderItem.children) folderItem.children.push(file)
        else folderItem.children = [file]
      }
    }
    folderItem.type = 'folder'
    return folderItem
  })
}

// 文件夹和文件夹存在嵌套关系,这里是将扁平的文件夹列表通过父子关系,转为树状结构,顶级的文件夹的folderId是0
// 过程分析:
//		首先,遍历出所有folderId是0的文件夹(找顶级的子级节点),
//      在找到一个folderId是0的文件夹时,同时也去找这个文件夹的所有子级节点(与找顶级的子级节点方法思路一致,因此就是递归查找),
//		找到子级节点后将子级节点加入到自己的children属性集合当中(如果在找之前,自己已经有了children属性,那就直接添加;否则就直接把找到的children作为自己的children),
export const transferFolderToTree = folderList => {

  if (!folderList.length) return []
  
  const folderListCloned = clonedeep(folderList)

  // 在js中方法中还可以定义一个方法
  const handle = id => {
  
    let arr = []
    
    folderListCloned.forEach(folder => {
    
      if (folder.folder_id === id) {
      
        const children = handle(folder.id)
        
        if (folder.children) {
        	folder.children = [].concat(folder.children, children)
       	}
       	else {
			folder.children = children
		}
		
        folder.title = folder.name
        
        arr.push(folder)
      }
    })
    
    return arr
  }
  return handle(0)
}

// 展开指定的文件夹(递归展开上级文件夹, 也就是如果一个节点被展开了,那么它的父节点也一定要展开)
export const expandSpecifiedFolder = (vm, folderTree, id) => {
  return folderTree.map(item => {
    if (item.type === 'folder') {
      if (item.id === id) {
        // item.expand = true
        vm.$set(item, 'expand', true)
      } else {
        if (item.children && item.children.length) {
          item.children = expandSpecifiedFolder(vm, item.children, id)
          if (item.children.some(child => {
            return child.expand === true
          })) {
            // item.expand = true
            vm.$set(item, 'expand', true)
          } else {
            // item.expand = false
            vm.$set(item, 'expand', false)
          }
        }
      }
    }
    return item
  })
}

TreeUtils

/**
 * @description
 * @Author: zzhua
 */
public class TreeUtils {
    /**
     * 对 实现TreeNode接口 的支持
     * @param treeNodes
     * @return
     */
    public static <T extends TreeNode> List<T> buildTreeNode(List<T> treeNodes) {
        HashMap<Long, TreeNode> map = new HashMap<>();
        // 将每个节点 以 id->regionTree的形式放入map中
        treeNodes.stream().forEach(e -> map.put(e.getId(), e));
        // 只需要遍历一遍treeArrayList: 从map中找到每一个节点对应的父节点(如果能找到的话),将此节点添加到对应的父节点的children中。
        // 经过这次遍历后,所有的节点都会添加到对应的父节点的children中
        treeNodes.stream().forEach(e->{
            Optional.ofNullable(map.get(e.getParentId())).ifPresent(p->{
                if (CollectionUtils.isEmpty(p.getChildren())) { // 保证子集合已初始化
                    p.setChildren(new ArrayList<>());
                }
                p.getChildren().add(e);
            });
        });
        return treeNodes;
    }

    /**
     * 将所有的节点依照父子级关系建立,建立好后,将不含父级(视为顶级)的节点返回
     * @param treeNodes
     * @return
     */
    public static <T extends TreeNode> List<T> filterTopTree(List<T> treeNodes) {
        HashMap<Long, TreeNode> map = new HashMap<>();
        // 将每个节点 以 id->regionTree的形式放入map中
        treeNodes.stream().forEach(e -> map.put(e.getId(), e));
        // 只需要遍历一遍treeArrayList: 从map中找到每一个节点对应的父节点(如果能找到的话),将此节点添加到对应的父节点的children中。
        // 经过这次遍历后,所有的节点都会添加到对应的父节点的children中
        List<Long> filterList = new ArrayList<>();
        treeNodes.stream().forEach(e->{
            Optional.ofNullable(map.get(e.getParentId())).ifPresent(p->{
                if (CollectionUtils.isEmpty(p.getChildren())) { // 保证子集合已初始化
                    p.setChildren(new ArrayList<>());
                }
                p.getChildren().add(e);
                filterList.add(e.getId()); // 记录有父级的节点(有父级,则该节点不应作为最外层的节点。只要不存在父级,都作为最外层的节点)
            });
        });
        return treeNodes.stream().filter(treeNode -> !filterList.contains(treeNode.getId())).collect(Collectors.toList());
    }
}

/**
 * @description 需要构建 树状结构数据 的类可以实现该接口,再调用{@link TreeUtils}
 * @Author: zzhua
 */
public interface TreeNode<T extends TreeNode> {

    /**
     * 返回 节点的 id
     * @return
     */
    Long getId();

    /**
     * 返回 节点的 父id
     * @return
     */
    Long getParentId();

    /**
     * 获取 节点下的子节点
     * @return
     */
    List<T> getChildren();

    /**
     * 设置 子节点 (防止因节点的子节点属性为null,而抛出的NPE异常)
     * @param list
     */
    void setChildren(List<T> list);

}

递归构建层级数据

@Override
public List<NewRegionTree> hierarchyRegionList(MerchantSubUserEntity user) {
    List<NewRegionTree> treeArrayList = new ArrayList<>();
    List<MerchantRegionCustomPropertyDTO> regionEntityList;
    //清缓存
    iAlarmRecordService.removeCache(1L);
    if (user.getUserType() == 0) {
        regionEntityList = baseMapper.selectHierarchyRegionByAdmin(user.getMerchantId());
    } else {
        regionEntityList = baseMapper.selectHierarchyRegion(user.getMerchantId(), user.getId());
    }
    BeanUtils.copyBeanList(regionEntityList, treeArrayList, NewRegionTree.class);

    //先找到一级父类,再通过级联去查询子类菜单
    List<NewRegionTree> regionTrees = treeArrayList.stream().filter(treeEntity ->
            treeEntity.getParentId() == 0     //查询父类
    ).map((treeEntity) -> {
        treeEntity.setHierarchyLevel(1);
        treeEntity.setChildren(getChildrenNew(treeEntity, treeArrayList, 1)); //查询子类菜单
        return treeEntity;
    }).collect(Collectors.toList());

    return regionTrees;
}

private static List<NewRegionTree> getChildrenNew(NewRegionTree regionTree, List<NewRegionTree> allTree, int hierarchyLevel) {
   int level = hierarchyLevel + 1;

    List<NewRegionTree> children = allTree.stream().filter(treeEntity -> {
        return treeEntity.getParentId().equals(regionTree.getId());
    }).map(treeEntity -> {
        //递归找到子菜单
        treeEntity.setHierarchyLevel(level);
        treeEntity.setChildren(getChildrenNew(treeEntity, allTree, level));
        return treeEntity;
    }).collect(Collectors.toList());

    return children;
}

private static List<NewRegionTree> getChildrenNew(NewRegionTree regionTree, List<NewRegionTree> allTree, int hierarchyLevel) {
    int level = hierarchyLevel + 1;

    List<NewRegionTree> children = allTree.stream().filter(treeEntity -> {
        return treeEntity.getParentId().equals(regionTree.getId());
    }).map(treeEntity -> {
        //递归找到子菜单
        treeEntity.setHierarchyLevel(level);
        treeEntity.setChildren(getChildrenNew(treeEntity, allTree, level));
        return treeEntity;
    }).collect(Collectors.toList());

    return children;
}




public List<NewRegionTree> hierarchyRegionList1(MerchantSubUserEntity user) {
    List<NewRegionTree> treeArrayList = new ArrayList<>();
    List<MerchantRegionCustomPropertyDTO> regionEntityList;
    if (user.getUserType() == 0) {
        regionEntityList = baseMapper.selectHierarchyRegionByAdmin(user.getMerchantId());
    } else {
        regionEntityList = baseMapper.selectHierarchyRegion(user.getMerchantId(), user.getId());
    }
    BeanUtils.copyBeanList(regionEntityList, treeArrayList, NewRegionTree.class);

    //先找到一级父类,再通过级联去查询子类菜单
    List<NewRegionTree> regionTrees = treeArrayList.stream().filter(treeEntity ->
            treeEntity.getParentId() == 0     //查询父类
    ).map((treeEntity) -> {
        treeEntity.setHierarchyLevel(1);
        treeEntity.setChildren(getChildrenNew1(treeEntity, treeArrayList, 1)); //查询子类菜单
        return treeEntity;
    }).collect(Collectors.toList());

    return regionTrees;
}

// 查找子级数据(新),只展示到第三级
private static List<NewRegionTree> getChildrenNew1(NewRegionTree regionTree, List<NewRegionTree> allTree, int hierarchyLevel) {
    int level = hierarchyLevel + 1;

    List<NewRegionTree> children = allTree.stream().filter(treeEntity -> {
        return treeEntity.getParentId().equals(regionTree.getId());
    }).map(treeEntity -> {
        //递归找到子菜单
        treeEntity.setHierarchyLevel(level);
        if (level != 3) {
            treeEntity.setChildren(getChildrenNew1(treeEntity, allTree, level));
        }
        return treeEntity;
    }).collect(Collectors.toList());

    return children;
}

private static List<NewRegionTree> getChildrenNew1(NewRegionTree regionTree, List<NewRegionTree> allTree, int hierarchyLevel) {
    int level = hierarchyLevel + 1;

    List<NewRegionTree> children = allTree.stream().filter(treeEntity -> {
        return treeEntity.getParentId().equals(regionTree.getId());
    }).map(treeEntity -> {
        //递归找到子菜单
        treeEntity.setHierarchyLevel(level);
        if (level != 3) {
            treeEntity.setChildren(getChildrenNew1(treeEntity, allTree, level));
        }
        return treeEntity;
    }).collect(Collectors.toList());

    return children;
}

<select id="selectHierarchyRegionByAdmin" resultType="com.anbao.ambientMonitor.data.dto.region.MerchantRegionCustomPropertyDTO">
    SELECT
        mr.id,
        mr.region_name AS label,
        mr.parent_id,
        mr.region_remark
    FROM
        merchant_region mr
       ,(SELECT @ids := 0) b
       ,(SELECT @ids AS _ids,(SELECT	@ids := GROUP_CONCAT(id) FROM merchant_region	WHERE	FIND_IN_SET(parent_id, @ids)) AS cids FROM merchant_region WHERE @ids IS NOT NULL ) a
    WHERE
        FIND_IN_SET(mr.id,a._ids)
      AND mr.merchant_id = #{merchantId}
      AND mr.region_classify = 1
      AND mr.is_del = 0
    ORDER BY CONVERT(mr.region_name USING gbk)
</select>

<select id="selectHierarchyRegion" resultType="com.anbao.ambientMonitor.data.dto.region.MerchantRegionCustomPropertyDTO">
    SELECT
        mr.id,
        mr.region_name AS label,
        mr.parent_id,
        mr.region_remark,
        mur.merchant_sub_user_id
    FROM
        merchant_user_region mur
        LEFT JOIN merchant_region mr ON mr.id = mur.merchant_region_id
       ,(SELECT @ids := 0) b
       ,(SELECT @ids AS _ids,(SELECT	@ids := GROUP_CONCAT(id) FROM merchant_region	WHERE	FIND_IN_SET(parent_id, @ids)) AS cids FROM merchant_region WHERE @ids IS NOT NULL ) a
    WHERE
        mur.merchant_sub_user_id = #{merchantUserId}
      AND FIND_IN_SET(mur.merchant_region_id,a._ids)
      AND mr.merchant_id = #{merchantId}
      AND mr.region_classify = 1
      AND mr.is_del = 0
    ORDER BY CONVERT(mr.region_name USING gbk)
</select>
    @Cacheable(value = "AreaPortal")
    @Override
    public String queryAllAreaJson() {
        AreaInfoCriteria criteria = new AreaInfoCriteria();
        List<AreaInfo> list = areaInfoDao.selectByCriteria(criteria);
        List<AreaInfo> collect = new LinkedList<>();
        for (AreaInfo areaInfo : list) {
            if (null != areaInfo.getParentCode() && areaInfo.getParentCode() == 0L) {
                areaInfo.setChildAreas(getChildren(areaInfo, list));
                collect.add(areaInfo);
            }
        }
        return JSONObject.toJSONString(collect);
    }

    /**
     * 递归查询子节点
     *
     * @param root 父节点
     * @param all  所有节点
     * @return
     */
    private List<AreaInfo> getChildren(AreaInfo root, List<AreaInfo> all) {
        List<AreaInfo> childAreas = new ArrayList<>();
        for (AreaInfo areaInfo : all) {
            if (null != areaInfo.getParentCode() && areaInfo.getParentCode().equals(root.getAreaCode())) {
                areaInfo.setChildAreas(getChildren(areaInfo, all));
                childAreas.add(areaInfo);
            }
        }
        return childAreas;
    }
/**
 * <p>Description:
 * 权限授权 Tree转换工具类
 *
 * @author zouwei
 * @date 2021/6/28
 */
public class AuthTreeUtil {

    /**
     * @return java.util.List<P>
     *  传递转换类,以及权限集合 返回格式化后的树形对象
     * @params uaaPermissionList
     * @author lx
     * @since 2021/6/10 14:45
     */
    public static List<UaaPermissionVO>  handlePermissionToMenuTree(List<UaaPermission> uaaPermissionList) {
        List<UaaPermissionVO> userMenuTreeList = new ArrayList<>();

        if (CollectionUtils.isEmpty(uaaPermissionList)) {
            return userMenuTreeList;
        }

        // 过滤出一级菜单的,一级菜单肯定是没有父级ID的
        List<UaaPermission> firstLevelMenu = uaaPermissionList.stream().filter(plist -> PermissionResType.MENU.getResType().equals(plist.getResType())).filter(plist -> StringUtils.isEmpty(plist.getParentId())).collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(firstLevelMenu)) {
            firstLevelMenu.stream().forEach(first -> {
                // 全路径
                first.setFullPathId(String.valueOf(first.getId()));
                filledTreeVo(userMenuTreeList, first, uaaPermissionList);
            });
        }


        return userMenuTreeList;
    }


    private static void filledTreeVo(List<UaaPermissionVO> userMenuTreeList, UaaPermission first, List<UaaPermission> uaaPermissionList) {

        UaaPermissionVO permissionVO = new UaaPermissionVO();
        permissionVO.setId(first.getId());
        permissionVO.setParentId(first.getParentId());
        permissionVO.setResCode(first.getResCode());
        permissionVO.setResName(first.getResName());
        permissionVO.setResType(first.getResType());
        permissionVO.setResSubType(first.getResSubType());
        permissionVO.setResUrl(first.getResUrl());
        permissionVO.setResId(first.getResId());
        permissionVO.setFullPathId(first.getFullPathId());
        permissionVO.setRuleName(first.getResName());
        permissionVO.setEnable(first.getEnable());
        permissionVO.setCheck(first.getCheck());
        permissionVO.setSystemId(first.getSystemId());

        userMenuTreeList.add(permissionVO);
        // 根据一级菜单 然后往下级查询
        recursionToConvertMenu(permissionVO, first, uaaPermissionList);
    }


    /**
     * @return void
     *  使用递归解析出所有的菜单出来
     * @params [userMenuTree, lastLevelMenu, uaaPermissionList]
     * @author lx
     * @since 2021/5/26 16:40
     */
    private static void recursionToConvertMenu(UaaPermissionVO userMenuTree, UaaPermission fatherLevelMenu, List<UaaPermission> uaaPermissionList) {

        List<UaaPermission> submenus = uaaPermissionList.stream().filter(fistList -> fatherLevelMenu.getId().equals(fistList.getParentId())).collect(Collectors.toList());
        //删除掉过滤的集合
        uaaPermissionList.removeAll(submenus);
        if (!CollectionUtils.isEmpty(submenus)) {
            List<UaaPermissionVO> childrenList = new ArrayList<>();
            submenus.forEach(submenu -> {
                // 父节点全路径+当前ID
                submenu.setFullPathId(fatherLevelMenu.getFullPathId() + "-" + submenu.getId());
                filledTreeVo(childrenList, submenu, uaaPermissionList);
            });
            userMenuTree.setChildren(childrenList);
        }

    }
    /**
     * 列表数据转换成树结构
     *
     * @param uaaPermissionList
     * @param externalId
     * @return
     */
    public static List<OpenPermissionVO> openPermissionTree(List<OpenPermissionVO> uaaPermissionList, String externalId) {

        List<OpenPermissionVO> permissionTreeList = new ArrayList<>();

        if (CollectionUtils.isEmpty(uaaPermissionList)) {
            return permissionTreeList;
        }
        List<OpenPermissionVO> firstLevelMenu = null;
        // 过滤出一级菜单的,一级菜单肯定是没有父级ID的
        if (StringUtils.isEmpty(externalId)){
           firstLevelMenu = uaaPermissionList.stream().filter(plist -> StringUtils.isEmpty(plist.getParentPermissionExternalId())).collect(Collectors.toList());
        } else {
            firstLevelMenu = uaaPermissionList.stream().filter(plist ->externalId.equals(plist.getPermissionExternalId())).collect(Collectors.toList());
        }
        if (!CollectionUtils.isEmpty(firstLevelMenu)) {
            firstLevelMenu.stream().forEach(first -> {
                permissionTree(permissionTreeList, first, uaaPermissionList);
            });
        }

        return permissionTreeList;
    }

    private static void permissionTree(List<OpenPermissionVO> userMenuTreeList, OpenPermissionVO permissionVO, List<OpenPermissionVO> uaaPermissionList) {
        userMenuTreeList.add(permissionVO);
        // 根据一级菜单 然后往下级查询
        childTree(permissionVO, permissionVO, uaaPermissionList);
    }

    private static void childTree(OpenPermissionVO userMenuTree, OpenPermissionVO fatherLevelMenu, List<OpenPermissionVO> uaaPermissionList) {
        if(uaaPermissionList==null)
        {
            return;
        }
        List<OpenPermissionVO> submenus = uaaPermissionList.stream().filter(fistList -> fatherLevelMenu.getPermissionExternalId().equals(fistList.getParentPermissionExternalId())).collect(Collectors.toList());
        //删除掉过滤的集合
        uaaPermissionList.removeAll(submenus);
        if (!CollectionUtils.isEmpty(submenus)) {
            List<OpenPermissionVO> childrenList = new ArrayList<>();
            submenus.forEach(submenu -> {
                permissionTree(childrenList, submenu, uaaPermissionList);
            });
            userMenuTree.setChildren(childrenList);
        }

    }

}

根据层级数据,查询某个节点的所有父级


  const list = [
    {
        path:'goods',
        title:'商品管理',
        children:[
             {
                path:'/specs',
                title:'商品规格'
            }
        ]
    },
    {
        path:'/system',
        title:'系统设置',
        children:[
            {
                path:'/menu',
                title:'菜单管理',
                children: [
                  {
                    path: '/icon',
                    title: '图标管理'
                  }
                ]
            },
            {
                path:'/role',
                title:'角色管理'
            },
        ]
    },
]

const parents = []

function findParent(targetPath,list,m) {
    if(list && list.length) {
        for (var i = 0; i < list.length; i++) {
            parents[m] = list[i];
            if(list[i].path === targetPath) {
                return
            } else if(list[i].children && list[i].children.length > 0 ){
                findParent(targetPath,list[i].children,m+1)
            }
        }
    }
}

findParent('/icon',list,0 )
console.log('----------------')
parents.forEach(e=>console.log(e.title))

递归获取拉平存储的树每个节点到达的路径

依赖

   <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-lang3</artifactId>
       <version>3.10</version>
   </dependency>

   <dependency>
       <groupId>org.projectlombok</groupId>
       <artifactId>lombok</artifactId>
       <version>1.18.16</version>
   </dependency>

   <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
   <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
       <version>31.1-jre</version>
   </dependency>

   <dependency>
       <groupId>com.alibaba</groupId>
       <artifactId>fastjson</artifactId>
       <version>1.2.68</version>
   </dependency>
/**
 * Copyright © 2016 my. All rights reserved.
 */
package com.zzhua;

import org.apache.commons.lang3.StringUtils;

import java.util.List;

import static com.google.common.base.Joiner.on;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.reverse;
import static java.text.MessageFormat.format;

/**
 * 获取到达树每个节点的路径
 *
 * @author James 2016年11月12日 下午4:14:58
 *
 */
public class TreePath {

	/**
	 * 根据平铺树计算路径
	 *
	 * @param nodes
	 */
	private static void genPath(List<Node> nodes) {

		for (Node node : nodes) {
			List<String> path = newArrayList();
			recurNode(nodes, node, node, path);
		}
	}

	/**
	 * 递归查找父节点
	 *
	 * @param nodes
	 *            所有节点
	 * @param targetNode
	 *            目标节点
	 * @param currentNode
	 *            当前节点
	 * @param path
	 *            路径
	 */
	private static void recurNode(List<Node> nodes, Node targetNode,
			Node currentNode, List<String> path) {
		if (StringUtils.equals(currentNode.getNodeNo(),
				currentNode.getParentNodeNo())) {
			throw new RuntimeException(format("非法的树结构,node:{0}",
					currentNode.getNodeNo()));
		}
		path.add(checkNotNull(emptyToNull(currentNode.getNodeCode()),
				format("节点编码为空,node:{0}", currentNode.getNodeNo())));
		// 终止条件,这里约定null,""表示根节点
		if (StringUtils.isBlank(currentNode.getParentNodeNo())) {
			targetNode.setPath(on(".").join(reverse(path)));
			return;
		}
		// 节点编号必须唯一,每次只能找到一个父节点
		for (Node node : nodes) {
			if (StringUtils.equals(currentNode.getParentNodeNo(),
					node.getNodeNo())) {
				recurNode(nodes, targetNode, node, path);
				return;
			}
		}
		// 既不是根节点又无法找到父节点
		throw new RuntimeException(format("非法的树结构,node:{0}",
				currentNode.getNodeNo()));

	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		List<Node> tree = newArrayList();

		// 第一颗课树
		tree.add(new Node("1", "A", ""));
		tree.add(new Node("2", "B", "1"));
		tree.add(new Node("3", "C", "2"));
		tree.add(new Node("4", "D", "3"));
		tree.add(new Node("5", "E", "1"));
		tree.add(new Node("6", "F", "2"));

		// 第二课树
		tree.add(new Node("11", "AA", ""));
		tree.add(new Node("22", "BB", "11"));
		tree.add(new Node("33", "CC", "22"));
		tree.add(new Node("44", "DD", "33"));
		tree.add(new Node("55", "EE", "11"));
		tree.add(new Node("66", "FF", "22"));
		tree.add(new Node("77", "GG", "66"));

		genPath(tree);

		for (Node node : tree) {
			System.out.println(node.getPath());
		}

	}

}

/**
 * 平铺的树 对应数据库中一条记录
 *
 * @author James 2016年11月12日 下午4:15:26
 *
 */
class Node {

	public Node(String nodeNo, String nodeCode, String parentNodeNo) {
		super();
		this.nodeNo = nodeNo;
		this.nodeCode = nodeCode;
		this.parentNodeNo = parentNodeNo;
	}

	/**
	 * 节点唯一编号
	 */
	private String nodeNo;

	/**
	 * 节点编码
	 */
	private String nodeCode;

	/**
	 * 父节点编码
	 */
	private String parentNodeNo;

	/**
	 * 根据元数据递归生成到达节点路径
	 */
	private String path;

	/**
	 * @return the nodeNo
	 */
	public String getNodeNo() {
		return nodeNo;
	}

	/**
	 * @param nodeNo
	 *            the nodeNo to set
	 */
	public void setNodeNo(String nodeNo) {
		this.nodeNo = nodeNo;
	}

	/**
	 * @return the nodeCode
	 */
	public String getNodeCode() {
		return nodeCode;
	}

	/**
	 * @param nodeCode
	 *            the nodeCode to set
	 */
	public void setNodeCode(String nodeCode) {
		this.nodeCode = nodeCode;
	}

	/**
	 * @return the parentNodeNo
	 */
	public String getParentNodeNo() {
		return parentNodeNo;
	}

	/**
	 * @param parentNodeNo
	 *            the parentNodeNo to set
	 */
	public void setParentNodeNo(String parentNodeNo) {
		this.parentNodeNo = parentNodeNo;
	}

	/**
	 * @return the path
	 */
	public String getPath() {
		return path;
	}

	/**
	 * @param path
	 *            the path to set
	 */
	public void setPath(String path) {
		this.path = path;
	}

}

输出结果

A
A.B
A.B.C
A.B.C.D
A.E
A.B.F
AA
AA.BB
AA.BB.CC
AA.BB.CC.DD
AA.EE
AA.BB.FF
AA.BB.FF.GG

根据拉平的树递归生成层次结构的树

/**
 * Copyright © 2016 my. All rights reserved.
 */
package com.zzhua;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;

import java.util.List;

/**
 * 根据拉平的树递归生成层次结构的树
 *
 * @author James 2016年11月14日 下午11:42:12
 *
 */
public class GenTree {

	/**
	 * 根据父节点获取所有子节点 如果父节点为null,则返回根节点
	 *
	 * @param node
	 * @return
	 */
	private static List<TreeNode> getChildNodes(final TreeNode parentNode,
			List<TreeNode> allNodes) {
		// 这里约定传入父节点为null就是查根节点
		Predicate<TreeNode> predicate = null;
		if (null == parentNode) {
			// 约定ParentNodeNo为 null,""是跟节点
			predicate = new Predicate<TreeNode>() {
				public boolean apply(TreeNode treeNode) {
					return Strings.isNullOrEmpty(treeNode.getParentNodeNo());
				}
			};
		} else {
			predicate = new Predicate<TreeNode>() {
				// 查询子节点
				public boolean apply(TreeNode treeNode) {
					return StringUtils.equals(parentNode.getNodeNo(),
							treeNode.getParentNodeNo());
				}
			};
		}
		return Lists.newArrayList(Iterables.filter(allNodes, predicate));

	}

	/**
	 * 根据父节点递归生成树
	 *
	 * @param parentNode
	 * @return
	 */
	private static TreeNode recurGenTree(TreeNode parentNode,
			List<TreeNode> allNodes) {
		// 查询子节点
		List<TreeNode> childNodes = getChildNodes(parentNode, allNodes);
		// 遍历子节点
		for (TreeNode child : childNodes) {
			TreeNode node = recurGenTree(child, allNodes);
			parentNode.getChildNodes().add(node);
		}
		return parentNode;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		List<TreeNode> tree = Lists.newArrayList();

		// 第一颗课树
		tree.add(new TreeNode("1", "A", ""));
		tree.add(new TreeNode("2", "B", "1"));
		tree.add(new TreeNode("3", "C", "2"));
		tree.add(new TreeNode("4", "D", "3"));
		tree.add(new TreeNode("5", "E", "1"));
		tree.add(new TreeNode("6", "F", "2"));

		// 第二课树
		tree.add(new TreeNode("11", "AA", ""));
		tree.add(new TreeNode("22", "BB", "11"));
		tree.add(new TreeNode("33", "CC", "22"));
		tree.add(new TreeNode("44", "DD", "33"));
		tree.add(new TreeNode("55", "EE", "11"));
		tree.add(new TreeNode("66", "FF", "22"));
		tree.add(new TreeNode("77", "GG", "66"));
		tree.add(new TreeNode("88", "HH", "77"));
		tree.add(new TreeNode("99", "II", "88"));

		// 查询根节点
		List<TreeNode> roots = getChildNodes(null, tree);
		for (TreeNode node : roots) {
			recurGenTree(node, tree);
		}

		for (TreeNode node : roots) {
			System.out.println(JSON.toJSONString(node));
		}

	}

}

/**
 * 拉平的树 对应数据库中一条记录
 *
 * @author James 2016年11月14日 下午11:45:50
 *
 */
class TreeNode {

	public TreeNode(String nodeNo, String nodeCode, String parentNodeNo) {
		super();
		this.nodeNo = nodeNo;
		this.nodeCode = nodeCode;
		this.parentNodeNo = parentNodeNo;
	}

	/**
	 * 节点唯一编号
	 */
	private String nodeNo;

	/**
	 * 节点编码
	 */
	private String nodeCode;

	/**
	 * 父节点编码
	 */
	private String parentNodeNo;

	private List<TreeNode> childNodes = Lists.newArrayList();

	/**
	 * 根据元数据递归生成到达节点路径
	 */
	private String path;

	/**
	 * @return the nodeNo
	 */
	public String getNodeNo() {
		return nodeNo;
	}

	/**
	 * @param nodeNo
	 *            the nodeNo to set
	 */
	public void setNodeNo(String nodeNo) {
		this.nodeNo = nodeNo;
	}

	/**
	 * @return the nodeCode
	 */
	public String getNodeCode() {
		return nodeCode;
	}

	/**
	 * @param nodeCode
	 *            the nodeCode to set
	 */
	public void setNodeCode(String nodeCode) {
		this.nodeCode = nodeCode;
	}

	/**
	 * @return the parentNodeNo
	 */
	public String getParentNodeNo() {
		return parentNodeNo;
	}

	/**
	 * @param parentNodeNo
	 *            the parentNodeNo to set
	 */
	public void setParentNodeNo(String parentNodeNo) {
		this.parentNodeNo = parentNodeNo;
	}

	/**
	 * @return the path
	 */
	public String getPath() {
		return path;
	}

	/**
	 * @param path
	 *            the path to set
	 */
	public void setPath(String path) {
		this.path = path;
	}

	/**
	 * @return the childNodes
	 */
	public List<TreeNode> getChildNodes() {
		return childNodes;
	}

	/**
	 * @param childNodes
	 *            the childNodes to set
	 */
	public void setChildNodes(List<TreeNode> childNodes) {
		this.childNodes = childNodes;
	}

}

输出结果

{"childNodes":[{"childNodes":[{"childNodes":[{"childNodes":[],"nodeCode":"D","nodeNo":"4","parentNodeNo":"3"}],"nodeCode":"C","nodeNo":"3","parentNodeNo":"2"},{"childNodes":[],"nodeCode":"F","nodeNo":"6","parentNodeNo":"2"}],"nodeCode":"B","nodeNo":"2","parentNodeNo":"1"},{"childNodes":[],"nodeCode":"E","nodeNo":"5","parentNodeNo":"1"}],"nodeCode":"A","nodeNo":"1","parentNodeNo":""}

{"childNodes":[{"childNodes":[{"childNodes":[{"childNodes":[],"nodeCode":"DD","nodeNo":"44","parentNodeNo":"33"}],"nodeCode":"CC","nodeNo":"33","parentNodeNo":"22"},{"childNodes":[{"childNodes":[{"childNodes":[{"childNodes":[],"nodeCode":"II","nodeNo":"99","parentNodeNo":"88"}],"nodeCode":"HH","nodeNo":"88","parentNodeNo":"77"}],"nodeCode":"GG","nodeNo":"77","parentNodeNo":"66"}],"nodeCode":"FF","nodeNo":"66","parentNodeNo":"22"}],"nodeCode":"BB","nodeNo":"22","parentNodeNo":"11"},{"childNodes":[],"nodeCode":"EE","nodeNo":"55","parentNodeNo":"11"}],"nodeCode":"AA","nodeNo":"11","parentNodeNo":""}

根据层级数据,获取到每个节点的父级节点

/**
 * @description 需要构建 树状结构数据 的类可以实现该接口,再调用{@link TreeUtils}
 * @Author: zzhua
 * @Date 2021/12/7
 */
public interface TreeNode<T extends TreeNode> {

    /**
     * 返回 节点的 id
     * @return
     */
    Long getId();

    /**
     * 返回 节点的 父id
     * @return
     */
    Long getParentId();

    /**
     * 获取 节点下的子节点
     * @return
     */
    List<T> getChildren();

    /**
     * 设置 子节点 (防止因节点的子节点属性为null,而抛出的NPE异常)
     * @param list
     */
    void setChildren(List<T> list);

}

/**
 * @description
 * @Author: zzhua
 * @Date 2021/12/30
 */
public class TreeUtils {
    /**
     * 对 实现TreeNode接口 的支持
     * @param treeNodes
     * @return
     */
    public static <T extends TreeNode> List<T> buildTreeNode(List<T> treeNodes) {
        HashMap<Long, TreeNode> map = new HashMap<>();
        // 将每个节点 以 id->regionTree的形式放入map中
        treeNodes.stream().forEach(e -> map.put(e.getId(), e));
        // 只需要遍历一遍treeArrayList: 从map中找到每一个节点对应的父节点(如果能找到的话),将此节点添加到对应的父节点的children中。
        // 经过这次遍历后,所有的节点都会添加到对应的父节点的children中
        treeNodes.stream().forEach(e->{
            Optional.ofNullable(map.get(e.getParentId())).ifPresent(p->{
                if (CollectionUtils.isEmpty(p.getChildren())) { // 保证子集合已初始化
                    p.setChildren(new ArrayList<>());
                }
                p.getChildren().add(e);
            });
        });
        return treeNodes;
    }

    /**
     * 将所有的节点依照父子级关系建立,建立好后,将不含父级(视为顶级)的节点返回
     * @param treeNodes
     * @return
     */
    public static <T extends TreeNode> List<T> filterTopTree(List<T> treeNodes) {
        HashMap<Long, TreeNode> map = new HashMap<>();
        // 将每个节点 以 id->regionTree的形式放入map中
        treeNodes.stream().forEach(e -> map.put(e.getId(), e));
        // 只需要遍历一遍treeArrayList: 从map中找到每一个节点对应的父节点(如果能找到的话),将此节点添加到对应的父节点的children中。
        // 经过这次遍历后,所有的节点都会添加到对应的父节点的children中
        List<Long> filterList = new ArrayList<>();
        treeNodes.stream().forEach(e->{
            Optional.ofNullable(map.get(e.getParentId())).ifPresent(p->{
                if (CollectionUtils.isEmpty(p.getChildren())) { // 保证子集合已初始化
                    p.setChildren(new ArrayList<>());
                }
                p.getChildren().add(e);
                filterList.add(e.getId()); // 记录有父级的节点(有父级,则该节点不应作为最外层的节点。只要不存在父级,都作为最外层的节点)
            });
        });
        return treeNodes.stream().filter(treeNode -> !filterList.contains(treeNode.getId())).collect(Collectors.toList());
    }
}

/**
 * @description
 * @Author: zzhua
 * @Date 2022/9/9
 */
public interface TreePathNode extends TreeNode {

    String getPathName();

    void setPathNames(List<String> pathNames);

    List<String> getPathNames();
}
public class TreePathUtil {

    // 传入未构建的树级列表
    public static <T extends TreePathNode> void buildPath(List<T> treeNodes) {

        if (!CollectionUtils.isEmpty(treeNodes)) {

            // 构建map
            HashMap<Long, TreePathNode> treeNodeMap = new HashMap<>();
            treeNodes.forEach(e -> treeNodeMap.put(e.getId(), e));

            // 临时存储递归结果(缓存优化)
            HashMap<Long, List<String>> tempResultPathNamesMap = new HashMap<>();

            for (TreePathNode treePathNode : treeNodes) {

                if (Objects.equals(treePathNode.getId(),treePathNode.getParentId())) {
                    throw new RuntimeException("非法树级结构数据: " + treePathNode.getId());
                }

                ArrayList<String> pathNames = new ArrayList<>();
                pathNames.add(treePathNode.getPathName());
                // 获取父节点
                findParentPathName(treePathNode, treeNodeMap,tempResultPathNamesMap, pathNames);
                // 走到这里, 说明(最初节点的)父节点已经递归找完了
                tempResultPathNamesMap.put(treePathNode.getId(), treePathNode.getPathNames());
                Collections.reverse(pathNames); // 倒序
                treePathNode.setPathNames(pathNames);
            }
        }

    }

    private static void findParentPathName(TreePathNode treePathNode,                     // 当前待查询的节点
                                           Map<Long, TreePathNode> treeNodeMap,           // 源Map数据
                                           Map<Long, List<String>> tempResultPathNamesMap,// 临时结果Map数组(缓存优化)
                                           List<String> pathNames) {                      // 路径
        if (tempResultPathNamesMap.containsKey(treePathNode.getId())) {
            Collections.addAll(tempResultPathNamesMap.get(treePathNode.getId()), pathNames.toArray(new String[0]));
            return;
        }
        TreePathNode parentTreePathNode = treeNodeMap.get(treePathNode.getParentId()); // 查询节点的父节点
        if (parentTreePathNode != null) {
            pathNames.add(parentTreePathNode.getPathName());
            findParentPathName(parentTreePathNode, treeNodeMap,tempResultPathNamesMap, pathNames); // 递归查询父节点
        }

    }

}

@Data
public class DeptAppletsListDto implements TreePathNode {

    @ApiModelProperty("组织id")
    private Long deptId;

    @ApiModelProperty("父级组织id")
    private Long parentId;

    @ApiModelProperty("组织名称")
    private String deptName;

    @ApiModelProperty("院区名称")
    private String hospitalAreaName;

    @ApiModelProperty("快速分类id")
    private Long fastClassifyId;

    @ApiModelProperty("父级路径集合")
    private List<String> pathNames = new ArrayList<>();

    @ApiModelProperty("子级")
    private List<DeptAppletsListDto> children = new ArrayList<>();

    @ApiModelProperty("创建时间")
    private Date createTime;

    @ApiModelProperty("排序值")
    private Integer sortIndex;

    @Override
    public String getPathName() {
        return deptName;
    }

    @Override
    public Long getId() {
        return deptId;
    }

    @Override
    public List<DeptAppletsListDto> getChildren() {
        return children;
    }

    @Override
    public void setChildren(List list) {
        this.children = list;
    }
}

 @ApiOperation("获取拉平的组织列表")
 @PostMapping("getFlattenedDeptList")
 public Result<List<DeptAppletsListDto>> getFlattenedDeptList(@Validated @RequestBody DeptAppletsQueryDto dto) {
     return Result.ok(deptService.getFlattenedDeptList(dto));
 }

@Override
public List<DeptAppletsListDto> getFlattenedDeptList(DeptAppletsQueryDto dto) {

     // 查询指定院区下的所有科室
     List<DeptAppletsListDto> deptAppletsListDtos = baseMapper.queryDeptListOfHospitalAreaId(dto);

     // 带上所有父级组成路径
     TreePathUtil.buildPath(deptAppletsListDtos);

     // 构建层级
     List<DeptAppletsListDto> topDeptAppletsListDtos = TreeUtils.filterTopTree(deptAppletsListDtos);

     List<DeptAppletsListDto> resultList = new ArrayList<>();

     // 拉平这棵树
     if (!CollectionUtils.isEmpty(topDeptAppletsListDtos)) {
         addChildrenToResultList(topDeptAppletsListDtos, resultList);
     }

     if (dto.getFastClassifyId() != null) {
         resultList = resultList.stream().filter(r -> Objects.equals(r.getFastClassifyId(), dto.getFastClassifyId())).collect(Collectors.toList());
     }

     Collections.sort(resultList, (dto1, dto2) -> {
         if (dto1.getSortIndex() != null && dto2.getSortIndex() != null) {
             if (!Objects.equals(dto1.getSortIndex(), dto2.getSortIndex())) {
                 return dto2.getSortIndex() - dto1.getSortIndex() > 0 ? 1 : -1;
             } else {
                 return dto2.getCreateTime().getTime() - dto1.getCreateTime().getTime() > 0 ? 1 : -1;
             }
         }
         return 0;
     });

     return resultList;
}

private void addChildrenToResultList(List<DeptAppletsListDto> deptAppletsDtoList, List<DeptAppletsListDto> resultList) {
    if (!CollectionUtils.isEmpty(deptAppletsDtoList)) {
        resultList.addAll(deptAppletsDtoList);
        for (DeptAppletsListDto deptAppletsListDto : deptAppletsDtoList) {
            List<DeptAppletsListDto> children = deptAppletsListDto.getChildren();
            if (!CollectionUtils.isEmpty(children)) {
                addChildrenToResultList(children, resultList);
            }
        }
    }
}
<select id="queryDeptListOfHospitalAreaId" resultType="com.anbao.train.data.dto.dept.DeptAppletsListDto">
    SELECT
        d.id AS deptId,
        d.parent_id,
        d.name AS deptName,
        ha.name AS hospitalAreaName,
        d.fast_classify_id,
        d.sort_index,
        d.create_time
    FROM
        dept d
            LEFT JOIN hospital_area ha on d.hospital_area_id = ha.id
    <where>
        d.is_del = 0
        <if test="dto.hospitalAreaId != null">
            AND d.hospital_area_id = #{dto.hospitalAreaId}
        </if>
    </where>
    ORDER BY
        d.sort_index DESC,
        d.create_time DESC
</select>

TreeNode树节点查找

/**
 * 树节点
 * @param <T>
 */
@Data
public class TreeNode<T> {

	/**
	 * 节点id
	 */
	private Long id;

	/**
	 * 节点名称
	 */
	private String name;

	/**
	 * 父节点id
	 */
	private Long parentId;

	/**
	 * 父节点名称
	 */
	private String parentName;

	/**
	 * 节点编码
	 */
	private String code;

	/**
	 * 节点排列序号
	 */
	private Integer sortNum;

	/**
	 * 节点值
	 */
	private T value;

	/**
	 * 节点全路径
	 */
	private String routeId;

	/**
	 * 子节点列表
	 */
	private List<TreeNode<T>> children = new ArrayList<>();

	/**
	 * 构造函数
	 */
	public TreeNode() {
	}

	public TreeNode(Long id, String name, String code, Long parentId, Integer sortNum, String routeId) {
		this.id = id;
		this.name = name;
		this.code = code;
		this.parentId = parentId;
		this.sortNum = sortNum;
		this.routeId = routeId;
	}

	/**
	 * 新增子节点
	 * @param treeNode
	 */
	public void addChildren(TreeNode<T> treeNode) {
		children.add(treeNode);
	}

	/**
	 * 根据节点名称查找树路径(当前仅支持最下级命中)
	 * @param nodeName
	 * @param currentIdPath
	 * @param matchedPaths
	 * @return
	 */
	public List<String> searchTree(String nodeName, List<String> currentIdPath, List<String> matchedPaths) {
		currentIdPath.add(String.valueOf(this.id));
		if (this.name.contains(nodeName)) {
			matchedPaths.add(String.join("->", currentIdPath));
		}
		for (TreeNode child : children) {
			child.searchTree(nodeName, new ArrayList<>(currentIdPath), matchedPaths);
		}
		return matchedPaths;
	}

	/**
	 * 当且仅当此节点(包括子级节点)中name字符串包含指定的字符值序列时,返回true
	 * @param value
	 * @return
	 */
	public boolean containsNameIncludeSon(String value) {
		if (this.name.contains(value)){
			return true;
		}
        for (TreeNode<T> child : this.children) {
            if (child.containsNameIncludeSon(value)) {
                return true;
            }
        }
        return false;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值