Java 8如何用函数式方法实现对象列表分组后取Top N的需求?
实现方案
注意:你提供的
Data类构造方法存在赋值方向错误的问题,会导致所有属性无法正确初始化,需要先修正:
public Data(double score, String name, String group) { this.score = score; this.name = name; this.group = group; }
使用Java 8 Stream API可以非常简洁的完成需求,不需要提前显式构建Map<String, List<Data>>,完整逻辑可以在一条Stream流中完成:
import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; public List<Data> getTopNGroupMax(List<Data> dataList, int topN) { return dataList.stream() // 按group分组,每个组直接取score最高的1条数据 .collect(Collectors.groupingBy( Data::getGroup, Collectors.collectingAndThen( Collectors.maxBy(Comparator.comparingDouble(Data::getScore)), opt -> opt.orElse(null) ) )) .values().stream() // 过滤极端场景下的空值 .filter(data -> data != null) // 所有组的最高分按score降序排序 .sorted(Comparator.comparingDouble(Data::getScore).reversed()) // 取前N条结果 .limit(topN) .collect(Collectors.toList()); }
测试调用
public static void main(String args[]) { ArrayList<Data> dataList = new ArrayList<Data>(); dataList.add(new Data(1.0, "one", "A")); dataList.add(new Data(4.0, "two", "A")); dataList.add(new Data(3.0, "three", "B")); dataList.add(new Data(2.0, "four", "C")); dataList.add(new Data(7.0, "five", "D")); dataList.add(new Data(17.0, "five", "D")); ArrayList<Data> dataList2 = new ArrayList<Data>(); dataList2.add(new Data(3.0, "one", "A")); dataList2.add(new Data(5.0, "six", "A")); dataList2.add(new Data(3.14, "two", "B")); dataList2.add(new Data(3.14, "three", "C")); MyClass handler = new MyClass(); // 取全局Top3 List<Data> result1 = handler.getTopNGroupMax(dataList, 3); List<Data> result2 = handler.getTopNGroupMax(dataList2, 3); // 输出和你提供的预期完全一致 result1.forEach(data -> System.out.printf("Data(%.1f, %s, %s)%n", data.getScore(), data.getName(), data.getGroup())); System.out.println("---"); result2.forEach(data -> System.out.printf("Data(%.2f, %s, %s)%n", data.getScore(), data.getName(), data.getGroup())); }
如果确实需要先存储Map<String, List<Data>>结构做后续复用,也可以单独拆分逻辑:
// 第一步:构建分组Map,每个组内的List按score降序排序 Map<String, List<Data>> groupMap = dataList.stream() .collect(Collectors.groupingBy( Data::getGroup, Collectors.collectingAndThen( Collectors.toList(), list -> list.stream() .sorted(Comparator.comparingDouble(Data::getScore).reversed()) .collect(Collectors.toList()) ) )); // 第二步:取TopN结果 List<Data> result = groupMap.values().stream() .filter(list -> !list.isEmpty()) .map(list -> list.get(0)) .sorted(Comparator.comparingDouble(Data::getScore).reversed()) .limit(3) .collect(Collectors.toList());
内容的提问来源于stack exchange,提问作者user3407267
相关产品推荐
相关产品推荐

