[JAVA] Die Geschichte von Collectors.groupingBy, die ich für die Nachwelt behalten möchte

Einführung

Der Titel ist großartig, aber Collectors.groupingBy ist einfach eine großartige Geschichte.

In letzter Zeit gab es viele Fälle, in denen verschiedene Karten mit groupingBy erstellt wurden (aus irgendeinem Grund gab es nur wenige Fälle, in denen Karten erstellt wurden, sodass ich sie nicht häufig verwendete). Dieser Artikel ist eine Zusammenfassung dessen, was zu dieser Zeit untersucht wurde.

Umgebung

Java10 Lombok

GroupingBy mit einem einfachen Schlüssel

Das Gute an Collectors.groupingBy ist, dass Sie sie einfach aggregieren können, indem Sie ihnen einen Schlüssel geben. Wenn Sie den Wert von Map ändern möchten, können Sie ein weiteres Argument hinzufügen und dort schreiben, sodass die Aggregation in verschiedenen Fällen unterstützt wird.

List<Integer> nums = List.of(1,2,3,4,5,6,7,8,9,1,1,1);
Map<Integer,List<Integer>> map = nums.stream().collect(Collectors.groupingBy(i ->i));
System.out.println(map);
=> {1=[1, 1, 1, 1], 2=[2], 3=[3], 4=[4], 5=[5], 6=[6], 7=[7], 8=[8], 9=[9]}

GroupingBy mit mehreren Schlüsseln

Das größte Merkmal von groupingBy ist jedoch, dass es auch dann gut funktioniert, wenn Sie komplizierte Schlüssel festlegen. Das Festlegen mehrerer Schlüssel ist sehr einfach. Übergeben Sie bei der Angabe der Schlüssel einfach mehrere Felder. "-" Wird hinzugefügt, um das Anzeigen zu vereinfachen, aber ohne ist es in Ordnung.

Als Schlüssel werden diesmal Name1 und Name2 als Schlüssel festgelegt.

    public static void main(String[] arg) {
        List<String> names = List.of("taro", "jiro", "saburo");

        List<Name> nameList = names.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
        
        Map<String,List<Name>> map = nameList.stream()
                .collect(Collectors.groupingBy(it -> it.getName1() + "-" + it.getName2()));
        System.out.println(map);
        // => {jiro-jiro=[Main.Name(name1=jiro, name2=jiro, name3=jiro)], saburo-saburo=[Main.Name(name1=saburo, name2=saburo, name3=saburo)], taro-taro=[Main.Name(name1=taro, name2=taro, name3=taro)]}
    }

    @Data
    private static class Name {
        private String name1;
        private String name2;
        private String name3;

        public Name(String name1, String name2, String name3) {
            this.name1 = name1;
            this.name2 = name2;
            this.name3 = name3;
        }
    }

Allein damit hat name3 den gleichen Wert, sodass Sie nicht erkennen können, ob name1 und name2 die Schlüssel sind. Daher möchte ich der Liste einen neuen Namen ("Taro", "Jiro", "Taro") hinzufügen und sehen, welche Art von Karte erstellt werden kann.

    public static void main(String[] arg) {
        List<String> names = List.of("taro", "jiro", "saburo");

        List<Name> nameList = names.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
        nameList.add(new Name("taro", "jiro", "taro"));

        Map<String,List<Name>> map = nameList.stream()
                .collect(Collectors.groupingBy(it -> it.getName1() + "-" + it.getName2()));
        System.out.println(map);
        // => {jiro-jiro=[Main.Name(name1=jiro, name2=jiro, name3=jiro)], saburo-saburo=[Main.Name(name1=saburo, name2=saburo, name3=saburo)], taro-taro=[Main.Name(name1=taro, name2=taro, name3=taro)], taro-jiro=[Main.Name(name1=taro, name2=jiro, name3=taro)]}
    }

Wie Sie dem Ergebnis entnehmen können, ist das diesmal hinzugefügte Objekt unabhängig als "taro-jiro = [Hauptname (Name1 = Taro, Name2 = Jiro, Name3 = Taro)]", also sind Name1 und Name2 Sie können sehen, dass es der Schlüssel war.

Was hier besorgniserregend ist, ist, dass der resultierende Name3 "Taro" enthält. Das Tolle an groupingBy ist, dass es dasselbe wie jedes andere Feld für andere Werte als die im Schlüssel angegebenen tut.

Ich möchte mit name1 und name3 als Schlüssel ausführen, um zu überprüfen, ob es wahr ist.

    public static void main(String[] arg) {
        List<String> names = List.of("taro", "jiro", "saburo");

        List<Name> nameList = names.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
        nameList.add(new Name("taro", "jiro", "taro"));

        Map<String,List<Name>> map = nameList.stream()
                .collect(Collectors.groupingBy(it -> it.getName1() + "-" + it.getName3()));
        System.out.println(map);
        // => {jiro-jiro=[Main.Name(name1=jiro, name2=jiro, name3=jiro)], saburo-saburo=[Main.Name(name1=saburo, name2=saburo, name3=saburo)], taro-taro=[Main.Name(name1=taro, name2=taro, name3=taro), Main.Name(name1=taro, name2=jiro, name3=taro)]}
    }

Wenn Sie das Ausführungsergebnis überprüfen, ist das als "neuer Name" ("Taro", "Jiro", "Taro") hinzugefügte Objekt "Taro-Taro = [Hauptname (Name1 = Taro, Name2 = Taro, Name3 = Taro)". ), Main.Name (name1 = taro, name2 = jiro, name3 = taro)] und wird wie erwartet als Wert des Schlüssels von taro-taro` registriert.

Wie weit können mehrere Schlüssel gehen?

Ich habe die Reihenfolge geändert

Schauen wir uns ein anderes Muster von Beispielen für Name1 und Name3 an. Sie können die Felder bis zum vorherigen Beispiel sehen, aber schauen wir uns auch das Beispiel an, in dem Name1 und Name3 vertauscht werden.

    public static void main(String[] arg) {
        List<String> names = List.of("taro", "jiro", "saburo");

        List<Name> nameList = names.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
        nameList.add(new Name("taro", "jiro", "taro"));
        nameList.add(new Name("jiro", "taro", "taro"));

        Map<String,List<Name>> map = nameList.stream()
                .collect(Collectors.groupingBy(it -> it.getName1() + "-" + it.getName3()));
        System.out.println(map);
        // => {jiro-jiro=[Main.Name(name1=jiro, name2=jiro, name3=jiro)], saburo-saburo=[Main.Name(name1=saburo, name2=saburo, name3=saburo)], jiro-taro=[Main.Name(name1=jiro, name2=taro, name3=taro)], taro-taro=[Main.Name(name1=taro, name2=taro, name3=taro), Main.Name(name1=taro, name2=jiro, name3=taro)]}
    }

Es scheint, dass selbst wenn Sie die Reihenfolge ändern, es richtig reagiert.

Ich habe es mit Integer versucht

Ich habe das vorherige Beispiel mit Integer-Typ versucht.

    public static void main(String[] arg) {
        List<Integer> nums = List.of(1,2,3);

        List<Name> nameList = nums.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
        nameList.add(new Name(1, 2, 1));
        nameList.add(new Name(2, 1, 1));

        Map<Integer,List<Name>> map = nameList.stream()
                .collect(Collectors.groupingBy(it -> it.getName1() + it.getName2()));
        System.out.println(map);
    }

    @Data
    private static class Name {
        private Integer name1;
        private Integer name2;
        private Integer name3;

        public Name(Integer name1, Integer name2, Integer name3) {
            this.name1 = name1;
            this.name2 = name2;
            this.name3 = name3;
        }
    }

In diesem Fall scheint es durch das Berechnungsergebnis des Schlüssels aggregiert zu werden. Es wäre seltsam, wenn es mehrere Schlüssel mit demselben Schlüssel gäbe, also bin ich überzeugt.

Ich habe es mit Integer Typ 2 versucht

Es scheint, dass es durch das Berechnungsergebnis aggregiert wird, aber überprüfen Sie für alle Fälle, ob Sie es im Feld sehen können.

    public static void main(String[] arg) {
        List<Integer> nums = List.of(1,2,3);

        List<Name> nameList = nums.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
        nameList.add(new Name(1, 1, 2));
        nameList.add(new Name(1, 2, 1));

        Map<Integer,List<Name>> map = nameList.stream()
                .collect(Collectors.groupingBy(it -> it.getName1() + it.getName3()));
        System.out.println(map);
        // => 2=[Main.Name(name1=1, name2=1, name3=1), Main.Name(name1=1, name2=2, name3=1)], 3=[Main.Name(name1=1, name2=1, name3=2)], 4=[Main.Name(name1=2, name2=2, name3=2)], 6=[Main.Name(name1=3, name2=3, name3=3)]}

    }

    @Data
    private static class Name {
        private Integer name1;
        private Integer name2;
        private Integer name3;

        public Name(Integer name1, Integer name2, Integer name3) {
            this.name1 = name1;
            this.name2 = name2;
            this.name3 = name3;
        }
    }

Er sah es auch in Integer-Typ.

Ich habe es mit Integer Typ 3 versucht

Dies ist der dritte Versuch vom Typ Integer. Angenommen, Sie konvertieren den Schlüssel in eine Zeichenfolge und verwenden ihn als Schlüssel.

    public static void main(String[] arg) {
        List<Integer> nums = List.of(1,2,3);

        List<Name> nameList = nums.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
        nameList.add(new Name(1, 2, 1));
        nameList.add(new Name(2, 1, 1));

        Map<String,List<Name>> map = nameList.stream()
                .collect(Collectors.groupingBy(it -> it.getName1() + "-" + it.getName2()));
        System.out.println(map);
        // => {1-1=[Main.Name(name1=1, name2=1, name3=1)], 2-1=[Main.Name(name1=2, name2=1, name3=1)], 1-2=[Main.Name(name1=1, name2=2, name3=1)], 2-2=[Main.Name(name1=2, name2=2, name3=2)], 3-3=[Main.Name(name1=3, name2=3, name3=3)]}
    }

    @Data
    private static class Name {
        private Integer name1;
        private Integer name2;
        private Integer name3;

        public Name(Integer name1, Integer name2, Integer name3) {
            this.name1 = name1;
            this.name2 = name2;
            this.name3 = name3;
        }
    }

In diesem Fall scheint die Reihenfolge berücksichtigt zu werden.

Versuchen Sie, 3 Schlüssel anzugeben

Lassen Sie uns prüfen, ob es kein Problem gibt, auch wenn wir die Anzahl der Schlüssel erhöhen.

    public static void main(String[] arg) {
        List<String> names = List.of("taro", "jiro", "saburo");

        List<Name> nameList = names.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
        nameList.add(new Name("taro","taro","jiro"));
        nameList.add(new Name("taro","jiro","taro"));

        Map<String,List<Name>> map = nameList.stream()
                .collect(Collectors.groupingBy(it -> it.getName1() + "-" + it.getName2() + "-" + it.getName3()));
        System.out.println(map);
        // => {jiro-jiro-jiro=[Main.Name(name1=jiro, name2=jiro, name3=jiro)], taro-jiro-taro=[Main.Name(name1=taro, name2=jiro, name3=taro)], taro-taro-taro=[Main.Name(name1=taro, name2=taro, name3=taro)], taro-taro-jiro=[Main.Name(name1=taro, name2=taro, name3=jiro)], saburo-saburo-saburo=[Main.Name(name1=saburo, name2=saburo, name3=saburo)]}

    }

    @Data
    private static class Name {
        private String name1;
        private String name2;
        private String name3;

        public Name(String name1, String name2, String name3) {
            this.name1 = name1;
            this.name2 = name2;
            this.name3 = name3;
        }
    }

Es scheint in Ordnung zu sein, die Anzahl der Schlüssel zu erhöhen.

Zusammenfassung

Ich dachte, ich würde ein bisschen mehr versuchen, aber jetzt, da ich die Tendenz begriffen habe, fasse ich abschließend die Operation des Aufstiegs zusammen.

Grundsätzlich scheint es sich um eine Methode zu handeln, die das im Schlüssel angegebene Feld gemäß dem Lambda-Ausdruck erstellt und nach diesem Wert aggregiert. Wenn es sich um einen Zeichenfolgentyp handelt, können Sie sehen, dass die angegebene Reihenfolge und das Feld verknüpft sind und der Schlüssel ist. Wenn es sich um einen numerischen Typ handelt, können Sie feststellen, ob das erstellte Ergebnis dasselbe ist, da das Berechnungsergebnis des angegebenen Felds der Schlüssel ist. Ich werde.

schließlich

Es stellt sich heraus, dass goupingBy wirklich mächtig ist. In Kombination mit anderen Methoden in Collectors kann es sogar noch stärker sein, aber ich möchte eine andere Gelegenheit nutzen (ich weiß nicht, ob es eine gibt).

Übrigens habe ich mich in diesem Artikel nicht mit der internen Verarbeitung von Java befasst, daher weiß ich nicht, warum dies passiert!

Recommended Posts

Die Geschichte von Collectors.groupingBy, die ich für die Nachwelt behalten möchte
Glassfish Tuning List, die ich vorerst behalten möchte
Ich möchte den Inhalt der Absicht var_dump
Ich möchte, dass Sie Enum # name () für den Schlüssel von SharedPreference verwenden
Ich möchte die Antwort der Janken-App wissen
Ich möchte den Namen des Posters des Kommentars anzeigen
Ich möchte die Bildlaufposition von UITableView zurückgeben!
Ich möchte die Protokollausgabeeinstellung von UtilLoggingJdbcLogger ändern
Ich möchte mehrere Rückgabewerte für das eingegebene Argument zurückgeben
[Ruby] Ich möchte die Reihenfolge der Hash-Tabelle umkehren
Ich möchte, dass Sie die Geschichte erzählen, dass der Fehler behoben wurde, als Sie das Ladegerät in die Ecke Ihres Kopfes gestochen haben
Ich möchte den Ablauf der Spring-Verarbeitungsanforderungsparameter verstehen
Ich möchte die Eingabe begrenzen, indem ich den Zahlenbereich einschränke
Ich möchte die Standardfehlermeldung von Spring Boot steuern
Ich möchte den Wert von Attribute in Selenium of Ruby ändern
Ich möchte die JSP des offenen Portlets bei der Entwicklung von Liferay kennen
Die Geschichte des Wechsels von Amazon RDS für MySQL zu Amazon Aurora Serverless
[Ruby] Ich möchte nur den Wert des Hash und nur den Schlüssel extrahieren
Die Geschichte der ersten Veröffentlichung der Android-App im Play Store.
Ich möchte das Argument der Annotation und das Argument der aufrufenden Methode an den Aspekt übergeben
Ich möchte den Feldnamen des [Java] -Felds erhalten. (Alter Ton)
Eine Geschichte, der ich mit der automatischen Starteinstellung von Tomcat 8 unter CentOS 8 zweimal verfallen war
Eine Geschichte, die ich mit der Stream-API von Java8 einem Prozess schreiben wollte, der einer while-Anweisung entspricht
Die Geschichte der Einführung der Ajax-Kommunikation in Ruby
Die Geschichte der Erhöhung der Spring Boot 1.5-Serie auf die 2.1-Serie
Die Geschichte des Hinzufügens der neuesten Node.js zu DockerFile
Ich möchte nach dem Dezimalpunkt abschneiden
Ich möchte den Wert in Ruby erhalten
[Android] Ich möchte einen ViewPager erstellen, der für Tutorials verwendet werden kann
Ich möchte, dass Sie Scala vorerst als besseres Java verwenden
Ich möchte den Inhalt der Anfrage sehen, ohne vier oder fünf zu sagen
Ich möchte rekursiv die Oberklasse und die Schnittstelle einer bestimmten Klasse erhalten
[Java] Ich möchte die Differenz zum Datum berechnen
Ich möchte eine TraceId in das Protokoll einbetten
Ich war süchtig nach der Aufzeichnung des zugehörigen Modells
Verstehe beim Lesen des Artikels! Zusammenfassung der Inhalte, die Elasticsearch-Anfänger unterdrücken möchten
05. Ich habe versucht, die Quelle von Spring Boot zu löschen
Ich möchte den Bereich anhand des monatlichen Abschlusses beurteilen
Ich habe versucht, die Kapazität von Spring Boot zu reduzieren
Ich möchte den Dunkelmodus mit der SWT-App verwenden
[Active Admin] Ich möchte den Umfang der Sammlung angeben, die in select_box angezeigt werden soll
[Rails] Ich möchte das Linkziel von link_to auf einer separaten Registerkarte anzeigen
Ich möchte die Hauptmethode mit Reflektion aufrufen
7 Dinge, die du behalten sollst, damit es kein verdammter Code wird