Java 8如何按名称排序并分组获取每组最高得分?
解决Record对象按name分组并取每组最高score的问题
嘿,我来帮你搞定这个需求!你现在的代码其实只是完成了排序+分组+展平的操作,并没有真正筛选出每个name对应的最高score的Record——最后得到的还是所有元素,只是按score排序后按name归了类,这显然不是你要的结果。
下面给你两种简洁高效的实现方式:
方法一:使用groupingBy + maxBy
直接在分组阶段就收集每组的最大值,不需要先排序再处理:
List<Record> result = list.stream() .collect(Collectors.groupingBy( Record::name, LinkedHashMap::new, // 保留原列表中name的出现顺序 Collectors.maxBy(Comparator.comparingInt(Record::score)) )) .values() .stream() .filter(Optional::isPresent) // 处理空分组的边界情况(你的示例里不会出现) .map(Optional::get) .collect(Collectors.toList());
代码说明:
groupingBy的第三个参数是下游收集器,用maxBy指定按score比较,直接拿到每组中score最大的Record;maxBy会返回Optional<Record>(防止分组为空的情况),所以需要用filter和map取出实际的Record对象;LinkedHashMap用来保证结果的顺序和原列表中name首次出现的顺序一致。
方法二:使用toMap合并重复项
这种方式更简洁,直接通过Map的合并规则保留最大值:
List<Record> result = new ArrayList<>(list.stream() .collect(Collectors.toMap( Record::name, Function.identity(), // 直接把Record作为value // 合并规则:当key重复时,保留score更大的那个Record (existingRecord, newRecord) -> existingRecord.score() > newRecord.score() ? existingRecord : newRecord, LinkedHashMap::new // 保持顺序 )) .values());
代码说明:
toMap的第三个参数是合并函数,遇到同一个name的Record时,我们比较两者的score,留下更大的那个;- 最后把Map的values转成ArrayList,就得到了每个name对应最高score的Record列表。
这两种方法都能直接得到你想要的结果:(a, 9) (b, 10) (c, 8),而且比你原来的代码更高效——不需要先排序整个列表,分组时就完成了最大值的筛选。
内容的提问来源于stack exchange,提问作者Shraddha
相关产品推荐
相关产品推荐

