[JAVA] Ich möchte Group By-Verarbeitung mit Stream durchführen (Group-by-Count, Group-by-Sum, Group-by-Max).

Angenommen, ein Benutzer und der von diesem Benutzer bezahlte Betrag werden in der folgenden Form angegeben:

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; }
}

Nun möchte ich für jeden Benutzer die Anzahl der Zahlungen, den gezahlten Gesamtbetrag oder den Höchstbetrag ermitteln. In SQL scheint es, dass Sie es leicht finden können, indem Sie "GROUP BY" und Fensterfunktion kombinieren, aber wie sollten Sie es in Java Stream schreiben?

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;

Die allgemeine Richtlinie lautet "Collectors.groupingBy". Erstens die Anzahl der Zahlungen, dh "Gruppierung nach Anzahl".

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

Es gibt eine bekannte Methode namens "Collectors.counting", daher scheint es gut, diese zu verwenden. Der als nächstes gezahlte Gesamtbetrag. Der Punkt ist "Gruppieren nach Summe", aber dies hat auch eine Methode mit dem beschreibenden Namen "Collectors.summingInt". Verwenden Sie also einfach diese.

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

Schließlich ist "maximal gezahlter Betrag" = "group-by-max", aber ich persönlich halte dies für den umstrittensten. Grundsätzlich scheint es schnell zu gehen, "Collectors.maxBy" zu verwenden.

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

Zu diesem Zeitpunkt ist der Typ der Variablen "maxs" "Map <String, Optional >". Optional ist wie ein Marker, der Sie darauf hinweist, dass er möglicherweise null ist, aber hier in der Geschäftslogik kann der Wert von maxs nicht null sein. Kurz gesagt, "Optional" macht hier nicht viel Sinn, deshalb möchte ich es loswerden. Mit anderen Worten, ich möchte den Typ von "maxs" auf "Map <String, Payment>" setzen, aber in einem solchen Fall scheint es schnell zu gehen, wie folgt vorzugehen.

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

An diesem Punkt beginnt das Gefühl der schwarzen Magie jedoch gut zu sein, daher möchte ich es moderieren (´ ・ ω ・ `).

Recommended Posts

Ich möchte Group By-Verarbeitung mit Stream durchführen (Group-by-Count, Group-by-Sum, Group-by-Max).
Ich möchte die Aggregationsverarbeitung mit Spring-Batch durchführen
Ich möchte eine asynchrone Verarbeitung und periodische Ausführung mit Rail durchführen !!!
[Java] Ich möchte mit dem Schlüssel im Objekt eindeutig arbeiten
Ich möchte DBViewer mit Eclipse 2018-12 verwenden! !!
Ich möchte nach Tabulatortrennzeichen mit Rubin sortieren
Ich möchte Java8 für jeden mit Index verwenden
Ich möchte mit Firestore von Rails spielen
[Rails] Ich möchte CSS mit Webpacker laden
Ich möchte eine von Git verwaltete Datei löschen
Ich habe versucht, was ich mit Stream leise versuchen wollte.
Listenverarbeitung zum Verstehen mit Bildern --java8 stream / javaslang-
Gelernter Stream (Ich möchte List in Map <Integer, List> konvertieren)
Ich möchte den Dunkelmodus mit der SWT-App verwenden
Ich möchte eine bestimmte Datei mit WatchService überwachen
Ich möchte eine Schleife schreiben, die auf einen Index mit der Stream-API von Java 8 verweist
Ich habe versucht, die Verarbeitungsgeschwindigkeit mit spiritueller Technik zu erhöhen
Ich möchte eine mit Rails 6 erstellte App an GitHub senden
Ich möchte eine Liste mit Kotlin und Java erstellen!
Ich möchte eine Funktion mit Kotlin und Java erstellen!
[Rails] Ich habe versucht, die Stapelverarbeitung mit der Rake-Task zu implementieren
Selbst in Java möchte ich true mit == 1 && a == 2 && a == 3 ausgeben
Ich möchte manuell eine Autorisierungs-E-Mail mit Devise senden
Listenverarbeitung zum Verstehen mit Bildern --java8 stream / javaslang --bonus
Ich möchte verschiedene Funktionen mit Kotlin und Java implementieren!
Ich möchte den Startbefehl mit Docker-Compose an Postgres übergeben.
[Java] Ich möchte Standardeingabe und Standardausgabe mit JUnit testen
Ich möchte Zeichen konvertieren ...
Ich möchte mit link_to [Hinweis] eine Schaltfläche mit einem Zeilenumbruch erstellen.
Ich möchte SONY Kopfhörer WH-1000XM4 mit LDAC mit Ubuntu 20.04 verbinden! !!
Ich möchte die Generierung / Öffnung einer Protokolldatei mit log4j # FileAppender verknüpfen
Ich möchte eine Browsing-Funktion mit Ruby on Rails hinzufügen
Ich möchte den Ablauf der Spring-Verarbeitungsanforderungsparameter verstehen
Ich möchte mit Kotlin und Java zum vorherigen Bildschirm zurückkehren!
Ich möchte Spring Local Time mit MySQL Time (auch Millisekunden) einfügen.
Ich möchte OutOfMemory bei der Ausgabe großer Dateien mit POI vermeiden
Ich möchte die Eingabe begrenzen, indem ich den Zahlenbereich einschränke
[Rails] Ich möchte beim Übergang mit link_to Daten zu Params hinzufügen
Ich möchte mit einem regulären Ausdruck zwischen Zeichenketten extrahieren
Ich habe versucht, mit Rails eine Gruppenfunktion (Bulletin Board) zu erstellen