如何使用Java流获取具有相同最大值的所有对象?

时间:2019-01-24 12:56:01

标签: java lambda java-stream

我有一些得分高手。我想使用流和过滤器让所有共享最大积分的玩家。

public class Player {
    private int points; // Getter omitted
}

我可以通过以下方法做到这一点:首先让得分最高的玩家,然后过滤所有具有相同数量的玩家。

Player topPlayer = players.stream().max(Comparator.comparing(Player::getPoints)).orElse(null);

players.stream().filter(p -> p.getPoints() == topPlayer.getPoints()).collect(Collectors.toList());

这可以用单个谓词/单行吗?

3 个答案:

答案 0 :(得分:8)

您可以先收集到TreeMap,然后才获得最后一个条目(最大值为

players.stream()
       .collect(Collectors.groupingBy(
           Player::getPoints,
           TreeMap::new,
           Collectors.toList()
       ))
       .lastEntry()
       .getValue();

答案 1 :(得分:5)

首先对这些点进行分组并获得Map结果,然后在map中找到最大键。时间成本将为O(n):

List<Player> players = new ArrayList<>();
players.stream().collect(Collectors.groupingBy(Player::getPoints))
        .entrySet().stream()
        .max(Map.Entry.comparingByKey())
        .ifPresent(System.out::println);

答案 2 :(得分:4)

这里是使用自定义收集器的版本。它庞大,丑陋且复杂,但是它在 O(n)中运行,仅对数据进行一次传递,并且几乎不需要额外的空间。

List<Player> highest = players.stream().collect(ArrayList::new, 
    (list, player) -> {
        if (list.isEmpty() || list.get(0).getPoints() == player.getPoints()) {
            list.add(player);
        } else if (list.get(0).getPoints() < player.getPoints()) {
            list.clear();
            list.add(player);
        }
    },
    (l1, l2) -> {
        if (l1.isEmpty()) {
            l1.addAll(l2);
        } else if (!l2.isEmpty()) {
            int cmp = Integer.compare(l1.get(0).getPoints(), l2.get(0).getPoints());
            if (cmp < 0) {
                l1.clear();
                l1.addAll(l2);
            } else if (cmp == 0) {
                l1.addAll(l2);
            }
        }
    });

累加器和合并器是关联的证明留给读者练习。


编辑:我试图编写一个更漂亮的合并器。我设法写的短而古怪。我相信它与上面的相同:

(l1, l2) -> {
    int cmp = l1.stream().findAny().flatMap(p1 -> l2.stream().findAny().map(
            p2 -> Integer.compare(p1.getPoints(), p2.getPoints()))).orElse(0);
    if (cmp < 0) l1.clear();
    if (cmp <= 0) l1.addAll(l2);
}