如何从分类树中获取指定ID的分类成员并保留完整上层树形结构
问题解决
现有代码问题
你的代码存在两个核心逻辑缺陷:
- 第一层筛选逻辑仅保留
level=1且ID等于目标ID的根节点,当目标节点是多级子节点时,根节点ID不可能匹配目标ID,无法返回上层层级 - 树构建逻辑会把父节点下所有子节点全部加入,不会过滤掉不包含目标节点的无关分支(比如示例中的
carnivores分支不应该出现在结果中)
实现思路
要保留目标节点的完整祖先层级,需要按以下逻辑处理:
- 先将平级的分类列表构建为完整的原始分类树
- 递归过滤树节点:仅保留当前节点为目标节点,或者子树中包含目标节点的分支,其余无关节点全部丢弃
可运行代码
import java.util.*; import java.util.stream.Collectors; // 对外调用方法:输入目标分类ID、平级全部分类列表,返回过滤后的层级树 private List<CategoryDTO> filterCategoryTreeById(String targetId, List<CategoryDTO> allCategories) { if (allCategories.isEmpty()) { return Collections.emptyList(); } // 1. 构建完整的原始分类树 List<CategoryDTO> fullTree = buildFullCategoryTree(allCategories); // 2. 过滤只保留包含目标ID的分支 return fullTree.stream() .map(node -> doFilter(node, targetId)) .filter(Objects::nonNull) .collect(Collectors.toList()); } // 构建完整分类树 private List<CategoryDTO> buildFullCategoryTree(List<CategoryDTO> allCategories) { // 按父ID分组,加速子节点查询 Map<String, List<CategoryDTO>> parentChildrenMap = allCategories.stream() .filter(item -> item.getParentId() != null) .collect(Collectors.groupingBy(CategoryDTO::getParentId)); // 筛选所有一级根节点,递归填充子节点 return allCategories.stream() .filter(item -> item.getLevel() == 1) .peek(root -> fillChildNodes(root, parentChildrenMap)) .collect(Collectors.toList()); } // 递归填充子节点 private void fillChildNodes(CategoryDTO parent, Map<String, List<CategoryDTO>> parentChildrenMap) { List<CategoryDTO> children = parentChildrenMap.getOrDefault(parent.getId(), Collections.emptyList()); parent.setChild(new ArrayList<>(children)); for (CategoryDTO child : children) { fillChildNodes(child, parentChildrenMap); } } // 递归过滤节点 private CategoryDTO doFilter(CategoryDTO currentNode, String targetId) { // 当前节点就是目标,直接返回 if (currentNode.getId().equals(targetId)) { return currentNode; } // 递归过滤所有子节点 List<CategoryDTO> filteredChildren = currentNode.getChild().stream() .map(child -> doFilter(child, targetId)) .filter(Objects::nonNull) .collect(Collectors.toList()); // 子节点不为空说明当前节点是目标的祖先节点,保留并替换为过滤后的子节点 if (!filteredChildren.isEmpty()) { currentNode.setChild(filteredChildren); return currentNode; } // 无关节点直接丢弃 return null; }
补充说明
你的实体类中字段名为title,如果需要JSON序列化后输出字段名为name,可以在title字段上添加@JsonProperty("name")注解即可。
内容的提问来源于stack exchange,提问作者Minh Nguyễn Nguyễn Đức
相关产品推荐
相关产品推荐

