3
votes

Comment compter les occurrences d'éléments dans une liste avec des ensembles?

Disons que j'ai une List<Set<String>> qui ressemble à ceci:

A: 1
B: 2
C: 3
D: 4
E: 3
F: 2
G: 1

Si je veux utiliser chaque valeur (A, B, C, D, E, F, G) dans chaque Set<String> dans cette List<Set<String>> et compter leur occurrence en les mappant, quel est un bon moyen pour moi de le mettre en œuvre? Je veux que la sortie ressemble à quelque chose comme:

[A,B,C,D]
[B,C,D,E]
[C,D,E,F]
[D,E,F,G]


0 commentaires

3 Réponses :


2
votes

À l'aide de l'API Stream, flatMap pour les ensembles internes doit être utilisé pour obtenir un flux de chaînes, puis une carte de fréquence est créée:

A=1
B=2
C=3
D=4
E=3
F=2
G=1

Production:

        
List<Set<String>> data = Arrays.asList(
    Set.of("A", "B", "C", "D"),
    Set.of("B", "C", "D", "E"),
    Set.of("C", "D", "E", "F"),
    Set.of("D", "E", "F", "G")
);
        
data.stream()
    .flatMap(Set::stream)
    .collect(Collectors.toMap(s -> s, s -> 1, Integer::sum, LinkedHashMap::new))
    .entrySet()
    .forEach(System.out::println);


0 commentaires

4
votes

Aplatissez simplement la liste en un seul flux et utilisez un collecteur groupingBy .

  • tout d'abord, diffusez simplement la liste. Cela crée un flux de listes plus petites.
  • alors vous devez les diffuser. Mais vous ne voulez pas de 4 flux de lettres. Vous voulez un flux de 16 lettres (ou la somme de tous les ensembles). C'est ce que fait flatMap. Il aplatit plusieurs flux en un seul.
  • alors vous voulez faire un comptage de fréquence. Vous souhaitez donc regrouper les lettres en utilisant elles-mêmes une clé. Par défaut groupingBy créerait une liste et mettrait les collisions (les valeurs associées aux clés en double) dans la liste.
  • mais vous ne voulez pas cela, donc le Collectors.counting() dit que si vous voyez une autre clé qui est déjà là, gardez simplement un compte et mettez à jour la valeur de 1. Vous comptez donc les occurrences des clés.
0=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
1=[1, 11, 21, 31, 41, 51, 61, 71, 81, 91]
2=[2, 12, 22, 32, 42, 52, 62, 72, 82, 92]
3=[3, 13, 23, 33, 43, 53, 63, 73, 83, 93]
4=[4, 14, 24, 34, 44, 54, 64, 74, 84, 94]
5=[5, 15, 25, 35, 45, 55, 65, 75, 85, 95]
6=[6, 16, 26, 36, 46, 56, 66, 76, 86, 96]
7=[7, 17, 27, 37, 47, 57, 67, 77, 87, 97]
8=[8, 18, 28, 38, 48, 58, 68, 78, 88, 98]
9=[9, 19, 29, 39, 49, 59, 69, 79, 89, 99]

Tirages

Map<Integer, List<Integer>> remainders =
        IntStream.range(0, 100).mapToObj(Integer::valueOf)
                .collect(Collectors.groupingBy(n -> n % 10));

remainders.entrySet().forEach(System.out::println); 

Voici un exemple simple du comportement groupingBy par défaut. Il met simplement les valeurs dans une liste en fonction de leurs restes lors de la division par 10 . IntStream génère un flux de int primitives afin qu'elles doivent être converties en un objet ( Integer dans ce cas) pour être collectées.

A=1
B=2
C=3
D=4
E=3
F=2
G=1

impressions

List<Set<String>> list = List.of(Set.of("A", "B", "C", "D"),
        Set.of("B", "C", "D", "E"),
        Set.of("C", "D", "E", "F"),
        Set.of("D", "E", "F", "G"));

Map<String, Long> freq =
        list.stream().flatMap(Set::stream).collect(Collectors
                .groupingBy(a -> a, Collectors.counting()));

freq.entrySet().forEach(System.out::println);


1 commentaires

Fonctionne parfaitement, mais pouvez-vous m'aider à élaborer un peu sur l'algorithme que vous avez implémenté dans la partie .collect ()?



3
votes
import java.util.*;
import java.util.function.Function;

import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;

0 commentaires