web-dev-qa-db-fra.com

Grouper en comptant dans Java 8 API de flux

J'essaie de trouver un moyen simple dans Java 8 API de flux pour faire le regroupement, je viens avec cette manière complexe!

List<String> list = new ArrayList<>();

list.add("Hello");
list.add("Hello");
list.add("World");

Map<String, List<String>> collect = list.stream().collect(
        Collectors.groupingBy(o -> o));
System.out.println(collect);

List<String[]> collect2 = collect
        .entrySet()
        .stream()
        .map(e -> new String[] { e.getKey(),
                String.valueOf(e.getValue().size()) })
        .collect(Collectors.toList());

collect2.forEach(o -> System.out.println(o[0] + " >> " + o[1]));

J'apprécie votre contribution.

141
Muhammad Hewedy

Je pense que vous cherchez juste le surcharge qui prend un autre Collector pour spécifier quoi faire avec chaque groupe ... et ensuite Collectors.counting() pour effectuer le comptage:

import Java.util.*;
import Java.util.stream.*;

class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        list.add("Hello");
        list.add("Hello");
        list.add("World");

        Map<String, Long> counted = list.stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

        System.out.println(counted);
    }
}

Résultat:

{Hello=2, World=1}

(Il y a aussi la possibilité d'utiliser groupingByConcurrent pour plus d'efficacité. Ce qu'il faut garder à l'esprit pour votre vrai code, s'il est sans danger dans votre contexte.)

284
Jon Skeet
List<String> list = new ArrayList<>();

list.add("Hello");
list.add("Hello");
list.add("World");

Map<String, List<String>> collect = list.stream()
                                        .collect(Collectors.groupingBy(o -> o));
collect.entrySet()
       .forEach(e -> System.out.println(e.getKey() + " - " + e.getValue().size()));
8
Sivakumar

Voici des options légèrement différentes pour accomplir la tâche à accomplir.

en utilisant toMap:

list.stream()
    .collect(Collectors.toMap(Function.identity(), e -> 1, Math::addExact));

en utilisant Map::merge:

Map<String, Integer> accumulator = new HashMap<>();
list.forEach(s -> accumulator.merge(s, 1, Math::addExact));
6
Aomine

Voici un exemple de liste d'objets

Map<String, Long> requirementCountMap = requirements.stream().collect(Collectors.groupingBy(Requirement::getRequirementType, Collectors.counting()));
5
fjkjava

Voici la solution simple par StreamEx

StreamEx.of(list).groupingBy(Function.identity(), Collectors.countingInt());

Réduisez le code passe-partout: collect(Collectors.

2
user_3380739

Si vous êtes prêt à utiliser une bibliothèque tierce, vous pouvez utiliser la classe Collectors2 dans Eclipse Collections pour convertir List en Bag à l'aide de Stream. A Bag est une structure de données qui est construite pour le comptage .

Bag<String> counted =
        list.stream().collect(Collectors2.countBy(each -> each));

Assert.assertEquals(1, counted.occurrencesOf("World"));
Assert.assertEquals(2, counted.occurrencesOf("Hello"));

System.out.println(counted.toStringOfItemToCount());

Sortie:

{World=1, Hello=2}

Dans ce cas particulier, vous pouvez simplement collect le List directement dans un Bag.

Bag<String> counted = 
        list.stream().collect(Collectors2.toBag());

Vous pouvez également créer Bag sans utiliser Stream en adaptant List avec les protocoles de collections Eclipse.

Bag<String> counted = Lists.adapt(list).countBy(each -> each);

ou dans ce cas particulier:

Bag<String> counted = Lists.adapt(list).toBag();

Vous pouvez également simplement créer le sac directement.

Bag<String> counted = Bags.mutable.with("Hello", "Hello", "World");

Un Bag<String> est comme un Map<String, Integer> en ce sens qu'il garde en interne le suivi des clés et de leur nombre. Mais si vous demandez à Map une clé qu’elle ne contient pas, elle renverra null. Si vous demandez à une clé Bag qu'elle ne contient pas avec occurrencesOf, elle retournera 0.

Remarque: Je suis un partisan des collections Eclipse.

1
Donald Raab