给定以下课程(针对问题的简化):
public static class Match { private final String type; private final int score; public Match(String type, int score) { this.type = type; this.score = score; } public String getType() { return type; } public int getScore() { return score; } }
我有一个Stream<Match>包含该类的多个实例的实例,同一类型出现多次,但得分不同:
Stream<Match>
Stream.of(new Match("A", 1), new Match("A", 2), new Match("A", 4), new Match("A", 10), new Match("B", 3), new Match("B", 6), new Match("B", 12), new Match("C", 1));
现在,我想收集流,以便结果List<Match>仅包含每种类型得分最高的实例。
List<Match>
以下代码可以正常工作,但是我不确定它是否是“最佳”解决方案(除了可怕的阅读和格式设置):
.collect(Collectors.collectingAndThen( Collectors.groupingBy(Match::getType, Collectors.collectingAndThen( Collectors.toList(), l -> l.stream().max(Comparator.comparing(Match::getScore)).get())), Map::values)) .forEach(m -> System.out.println(m.getType() + ": " + m.getScore()));
和:
.collect(Collectors.collectingAndThen( Collectors.groupingBy(Match::getType, Collectors.maxBy(Comparator.comparing(Match::getScore))), Map::values)) .forEach(m -> m.ifPresent(ma -> System.out.println(ma.getType() + ": " + ma.getScore())));
输出(正确):
A:10 B:12 C:1
另外,我无法提取返回收集器的通用静态方法,因此我可以通过以下方式简单地在需要的地方使用它: .collect(distinctMaxByProperty(Match::getType, Match::getScore)
.collect(distinctMaxByProperty(Match::getType, Match::getScore)
任何帮助将不胜感激!
List当您可以首先收集最大元素时,请勿收集到中,而只是提取一个值,例如
List
Map<String,Match> result = Stream.of(new Match("A", 1), new Match("A", 2), new Match("A", 4), new Match("A", 10), new Match("B", 3), new Match("B", 6), new Match("B", 12), new Match("C", 1)) .collect(Collectors.groupingBy(Match::getType, Collectors.collectingAndThen( Collectors.reducing(BinaryOperator.maxBy( Comparator.comparingInt(Match::getScore))), Optional::get)));
但是,每当您需要Optional在的上下文中提取时groupingBy,都值得检查是否具有合并功能的toMap`是否可以给出更简单的结果:
Optional
groupingBy
Map<String,Match> result = Stream.of(new Match("A", 1), new Match("A", 2), new Match("A", 4), new Match("A", 10), new Match("B", 3), new Match("B", 6), new Match("B", 12), new Match("C", 1)) .collect(Collectors.toMap(Match::getType, Function.identity(), BinaryOperator.maxBy(Comparator.comparingInt(Match::getScore))));
一旦有了,Map您可以通过以下方式产生所需的输出
Map
result.values().forEach(m -> System.out.println(m.getType() + ": " + m.getScore()));
但是,如果您不需要实际的Match实例,则可以做得更简单:
Match
Stream.of(new Match("A", 1), new Match("A", 2), new Match("A", 4), new Match("A", 10), new Match("B", 3), new Match("B", 6), new Match("B", 12), new Match("C", 1)) .collect(Collectors.toMap(Match::getType, Match::getScore, Math::max)) .forEach((type,score) -> System.out.println(type + ": " + score));