Java流处理:如果没有重复项,则获取最大值

4
我正在尝试编写一个函数,它接收一个 Map 并返回一个 Entry。如果拥有最大 Integer 值的 entry 是唯一的,那么它应该返回该条 entry。但是,如果存在具有相同最大值的重复项,则应返回一个新的 Entry,其键为“MULTIPLE”,值为 0。对于我来说,忽略重复项并获取最大值很容易:
public static Entry<String,Integer> getMax(Map<String,Integer> map1) {
    return map1.entrySet().stream()
                          .max((a,b) -> a.getValue().compareTo(b.getValue()))
                          .get();
}

但是为了实现我最初说的那样,我只能找到一种解决方案,即创建一个初始流来进行布尔检查以查看是否存在多个最大值,如果不存在,则使用另一个流获取该值。 我希望找到一种解决方案,可以在一个流中完成这两个任务。

这是我的小测试案例:

   @Test
   public void test1() {
         Map<String,Integer> map1 = new HashMap<>();
         map1.put("A", 100);
         map1.put("B", 100);
         map1.put("C", 100);
         map1.put("D", 105);

         Assert.assertEquals("D", getMax(map1).getKey());

         Map<String,Integer> map2 = new HashMap<>();
         map2.put("A", 100);
         map2.put("B", 105);
         map2.put("C", 100);
         map2.put("D", 105);

         Assert.assertEquals("MULTIPLE", getMax(map2).getKey());

两个数据流有什么问题吗?为什么要将它合并成一个? - Joe C
没问题。我只是想知道是否可能,如果可能的话,如何实现。 - wlaem
2个回答

1

以下是 StreamEx 提供的解决方案。

public Entry<String, Integer> getMax(Map<String, Integer> map) {
    return StreamEx.of(map.entrySet()).collect(collectingAndThen(MoreCollectors.maxAll(Map.Entry.comparingByValue()),
            l -> l.size() == 1 ? l.get(0) : new AbstractMap.SimpleImmutableEntry<>("MULTIPLE", 0)));
}

另一种解决方案是使用两次迭代地图,可能会获得更好的性能:
public Entry<String, Integer> getMax(Map<String, Integer> map) {
    int max = map.entrySet().stream().mapToInt(e -> e.getValue()).max().getAsInt();

    return StreamEx.of(map.entrySet()).filter(e -> e.getValue().intValue() == max).limit(2)
            .toListAndThen(l -> l.size() == 1 ? l.get(0) : new AbstractMap.SimpleImmutableEntry<>("MULTIPLE", 0));
}

1
你好。我们注意到你最近的回答几乎都在推广第三方库StreamEx。总体来看,你的回答完整且与问题相关,所以感谢你试图遵循我们的指南。然而,如果你与StreamEx有关联,你需要在回答中明确披露你的关联。否则,社区往往会认为这是垃圾邮件或“草根营销”,这在这里是不受欢迎的。 - Cody Gray
我与StreamEx没有任何关联。唯一的原因是StreamEx是一个非常好的库,可以/应该用来解决许多Java 8流API相关的问题。 - 123-xyz
好的,没问题。我们刚刚收到一些用户的反馈,他们怀疑你几乎所有的答案都在推广这个库。也许你可以回答一些其他类型的问题? :-) 正如我所说的,你已经很好地展示了这个库是如何解决问题的,所以继续保持好工作。 - Cody Gray

1
这是一个简单的缩减案例,无需使用任何外部库。
Map.Entry<String, Integer> max(Map<String, Integer> map) {
    return map.entrySet().stream()
            .reduce((e1, e2) -> {
                if (e1.getValue() == e2.getValue()) {
                    return new SimpleImmutableEntry<>("MULTIPLE", 0);
                } else {
                    return Collections.max(asList(e1, e2), comparingInt(Map.Entry::getValue));
                }
            })
            .orElse(new SimpleImmutableEntry<>("NOT_FOUND", 0));
}

1
好主意,你不需要使用:Collections.max(asList(e1, e2), comparingInt(Map.Entry::getValue)); e1.getValue() > e2.getValue() ? e1 : e2就足够了。 - 123-xyz
1
很有趣...实际上我认为答案是错误的。 - 123-xyz
加油...我添加了第一个评论,因为如果地图的大小为一百万,则将创建一百万个临时SimpleImmutableEntry/List。这是显而易见的,完全没有必要。其次,再次回答是错误的,如何?自己找出来。你的回应不友好,没有必要再与你争论。 - 123-xyz
@123-xyz OP并没有要求解决方案适用于大型地图,这种情况下可以进行多项优化。至于友好,您来到了错误的网站;请尝试matchdotcom。 - Abhijit Sarkar
你的意思是他不应该调用asList(),因为如果有一百万个项目要比较,那么可能会创建一百万个列表...是这个意思吗? - wlaem
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接