[JAVA] Je souhaite effectuer un traitement Group By avec Stream (group-by-count, group-by-sum, group-by-max)

Par exemple, supposons qu'un utilisateur et le montant payé par cet utilisateur soient donnés sous la forme suivante:

public class Payment {
    
    public static void main(String[] args) {
        var payments = List.of(
            new Payment("A", 10),
            new Payment("B", 20),
            new Payment("B", 30),
            new Payment("C", 40),
            new Payment("C", 50),
            new Payment("C", 60)
        );
    }

    private String name;
    private int value;
    
    public Payment(String name, int value) {
        this.name = name;
        this.value = value;
    }
    public String getName() { return name; }
    public int getValue() { return value; }
}

Maintenant, pour chaque utilisateur, je voudrais trouver le nombre de paiements, le montant total payé ou le montant maximum. En SQL, il semble que vous puissiez facilement le trouver en combinant GROUP BY et la fonction de fenêtre, mais comment l'écrire dans Java Stream?

select name, count(*) from payment group by name;
select name, sum(value) from payment group by name;
select name, max(value) from payment group by name;

La politique générale consiste à utiliser Collectors.groupingBy. Premièrement, le nombre de paiements, c'est-à-dire «group-by-count».

var counts = payments.stream().collect(Collectors.groupingBy(Payment::getName, Collectors.counting()));
counts.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).forEach(System.out::println);
// A=1
// B=2
// C=3

Il existe une méthode bien connue appelée Collectors.counting, donc il semble bon de l'utiliser. Le montant total payé ensuite. Le point est group-by-sum, mais cela a également une méthode avec un nom descriptif de Collectors.summingInt, alors utilisez simplement ceci.

var sums = payments.stream().collect(Collectors.groupingBy(Payment::getName, Collectors.summingInt(Payment::getValue)));
sums.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).forEach(System.out::println);
// A=10
// B=50
// C=150

Enfin, "montant maximum payé" = "group-by-max", mais je pense personnellement que c'est le plus controversé. En tant que politique de base, il semble être rapide d'utiliser Collectors.maxBy.

var maxs = payments.stream().collect(Collectors.groupingBy(Payment::getName, Collectors.maxBy(Comparator.comparingInt(Payment::getValue))));
maxs.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue().get().getValue()).forEach(System.out::println);
// A=10
// B=30
// C=60

À ce stade, le type de la variable «maxs» est «Map <String, Optional >». ʻOptional est comme un marqueur qui vous avertit qu'il peut être nul, mais ici dans la logique métier, la valeur de maxsne peut pas être nulle. En bref, «facultatif» ici n'a pas beaucoup de sens, donc je veux m'en débarrasser. En d'autres termes, je veux définir le type demaxs sur Map <String, Payment>`, mais dans un tel cas, il semble être rapide de faire comme suit.

var maxs = payments.stream().collect(Collectors.groupingBy(Payment::getName, Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(Payment::getValue)), Optional::get)));
maxs.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue().getValue()).forEach(System.out::println);
// A=10
// B=30
// C=60

Cependant, à ce stade, la sensation de magie noire commence à être bonne, alors je veux la modérer (´ ・ ω ・ `)

Recommended Posts

Je souhaite effectuer un traitement Group By avec Stream (group-by-count, group-by-sum, group-by-max)
Je souhaite effectuer un traitement d'agrégation avec spring-batch
Je souhaite effectuer un traitement asynchrone et une exécution périodique avec Rail !!!
[Java] Je veux effectuer distinctement avec la clé dans l'objet
Je souhaite utiliser DBViewer avec Eclipse 2018-12! !!
Je veux trier par délimiteur d'onglet avec ruby
Je veux utiliser java8 forEach avec index
Je veux jouer avec Firestore de Rails
[Rails] Je veux charger du CSS avec webpacker
Je souhaite supprimer un fichier géré par Git
J'ai essayé ce que je voulais essayer avec Stream doucement.
Traitement des listes à comprendre avec des images - java8 stream / javaslang-
Flux appris (je veux convertir la liste en carte <Integer, List>)
Je souhaite utiliser le mode sombre avec l'application SWT
Je souhaite surveiller un fichier spécifique avec WatchService
Je veux écrire une boucle qui fait référence à un index avec l'API Stream de Java 8
J'ai essayé d'augmenter la vitesse de traitement avec l'ingénierie spirituelle
Je veux pousser une application créée avec Rails 6 vers GitHub
Je veux faire une liste avec kotlin et java!
Je veux créer une fonction avec kotlin et java!
[Rails] J'ai essayé d'implémenter le traitement par lots avec la tâche Rake
Même en Java, je veux afficher true avec un == 1 && a == 2 && a == 3
Je souhaite envoyer manuellement un e-mail d'autorisation avec Devise
Traitement des listes à comprendre avec des images --java8 stream / javaslang --bonus
Je veux implémenter diverses fonctions avec kotlin et java!
Je veux passer la commande de démarrage à postgres avec docker-compose.
[Java] Je souhaite tester l'entrée standard et la sortie standard avec JUnit
Je veux convertir des caractères ...
Je veux créer un bouton avec un saut de ligne avec link_to [Note]
Je veux connecter un casque SONY WH-1000XM4 avec LDAC avec ubuntu 20.04! !!
Je veux accrocher la génération / ouverture d'un fichier journal avec log4j # FileAppender
Je souhaite ajouter une fonction de navigation avec ruby on rails
Je veux comprendre le flux des paramètres de demande de traitement Spring
Je veux revenir à l'écran précédent avec kotlin et java!
Je veux INSÉRER l'heure locale du printemps avec l'heure MySQL (également en millisecondes)
Je veux éviter OutOfMemory lors de la sortie de gros fichiers avec POI
Je veux limiter l'entrée en réduisant la plage de nombres
[Rails] Je souhaite ajouter des données aux paramètres lors de la transition avec link_to
Je veux extraire entre des chaînes de caractères avec une expression régulière
J'ai essayé de créer une fonction de groupe (babillard) avec Rails