如何用Lambda从列表中移除复合ID的较小子项并保留最大项
解决方法:用Stream分组+筛选最大值
要实现你的需求,核心思路是按前缀分组,再在每组里保留后缀数值最大的Document,用Stream的groupingBy配合maxBy就能搞定,比你用reduce更直接。
具体步骤&代码示例
假设你的Document类有getDocumentId()方法获取复合ID,代码如下:
import java.util.List; import java.util.Objects; import java.util.Comparator; import java.util.stream.Collectors; // 处理逻辑 List<Document> filteredDocuments = object.getDocuments().stream() // 1. 按前缀分组:key是前缀字符串,value是同前缀的Document列表 .collect(Collectors.groupingBy(doc -> { String[] parts = doc.getDocumentId().split("-"); return parts[0]; // 提取前缀 })) // 2. 遍历每个分组,筛选出后缀最大的Document .values().stream() .map(group -> group.stream() .max(Comparator.comparingInt(doc -> { String[] parts = doc.getDocumentId().split("-"); return Integer.parseInt(parts[1]); // 转成整数比较大小 })) .orElse(null)) // 处理空分组的边界情况(实际业务中一般不会出现) .filter(Objects::nonNull) // 过滤掉空值 .collect(Collectors.toList());
代码解释
- 分组阶段:用
groupingBy把所有Document按前缀归类,比如前缀521的所有文档会被放到同一个列表里。 - 筛选最大值:对每个分组,用
max()方法配合自定义比较器——把每个Document的后缀转成整数,比较后留下数值最大的那个。 - 收集结果:把每个分组的最大值收集成最终的过滤列表。
为什么你的伪代码不行?
reduce是用来把流中的元素逐步合并成单个结果的,适合求和、字符串拼接这类操作,但不适合这种多分组筛选的场景——它没法同时处理多个前缀的分组逻辑,很容易丢失其他前缀的元素。
优化小技巧
如果不想重复写拆分ID的代码,可以抽成工具方法简化逻辑:
// 提取前缀的工具方法 private static String getPrefix(Document doc) { return doc.getDocumentId().split("-")[0]; } // 提取后缀并转成整数的工具方法 private static int getSuffixAsInt(Document doc) { return Integer.parseInt(doc.getDocumentId().split("-")[1]); }
之后处理代码会更简洁:
List<Document> filteredDocuments = object.getDocuments().stream() .collect(Collectors.groupingBy(YourCurrentClass::getPrefix)) .values().stream() .map(group -> group.stream() .max(Comparator.comparingInt(YourCurrentClass::getSuffixAsInt)) .orElse(null)) .filter(Objects::nonNull) .collect(Collectors.toList());
内容的提问来源于stack exchange,提问作者Talenel
相关产品推荐
相关产品推荐

