Java Streaming: obtenez max si aucun doublon


J'essaie d'écrire une fonction qui prend une carte et renvoie une entrée. Si l'entrée avec la valeur entière maximale est unique, elle doit renvoyer cette entrée. Cependant, s'il y a des entrées en double avec la même valeur max, il devrait renvoyer une nouvelle entrée avec une clé de "MULTIPLE" et une valeur de 0. Il est assez facile pour moi d'obtenir la valeur maximale en ignorant les doublons:

public static Entry<String,Integer> getMax(Map<String,Integer> map1) {
    return map1.entrySet().stream()
                          .max((a,b) -> a.getValue().compareTo(b.getValue()))
                          .get();
}

Mais pour que je fasse ce que j'ai dit au départ, je ne pouvais trouver qu'une solution où je devais créer une initiale flux pour effectuer une vérification booléenne s'il y avait plusieurs valeurs max, puis faire un autre flux sinon pour obtenir la valeur. Je voudrais trouver une solution où je peux faire les deux tâches avec un seul flux.

Voici mon petit cas de test:

   @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());
Author: Stefan Zobel, 2017-08-11

2 answers

C'est un cas simple de réduction, et vous n'avez pas besoin de bibliothèques externes.

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
Author: Abhijit Sarkar, 2017-08-11 04:37:05

Voici la solution par 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)));
}

Une autre solution consiste à itérer la carte deux fois avec de meilleures performances potentielles:

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
Author: 123-xyz, 2017-08-11 04:36:26