Listenverarbeitung zum Verstehen mit Bildern --java8 stream / javaslang --bonus

Listenverarbeitung unter Bildern verstanden --java8 stream / javaslang- Zusätzlicher Artikel!

Es war wie immer zu lang, also habe ich es getrennt.

Lass uns grob gehen!

[Bonus-Java8-Stream]: Andere reduzieren

Es gibt drei Definitionen von "Reduzieren" im Java8-Stream:

Ich werde die beiden anderen vorstellen.

Das erste ist das.

Optional<T> reduce(BinaryOperator<T> accumulator);

Optional<T> reduce(     ((T, T) -> T) f);            //Vereinfachung
         T  reduce(T t, ((T, T) -> T) f);            //Repost der ersten reduzieren

Der Unterschied besteht darin, dass es kein "T t" gibt und die Rückgabe in "Optional" verpackt ist.

Sie können sehen, warum dies passiert, indem Sie sich das Bild ansehen.

Diejenigen, die das erste "T t" haben reduce with zero a.png

Diejenigen, die kein "T t" haben reduce with head.png

Der Unterschied zwischen der Angabe des Anfangswertes selbst und der Verwendung des ersten als Anfangswert ist der Unterschied in der Anwesenheit oder Abwesenheit von "T t".

Sie können also sehen, warum die Rückgabe "optional" ist, indem Sie den Fall einer leeren Liste betrachten.

Wenn die Liste leer ist, kann "T t" das Endergebnis sein reduce with zero empty.png

Nichts passiert, wenn es kein "T t" gibt und die Liste leer ist reduce with head empty.png

Dies liegt daran, dass eine Rückgabe nicht vorbereitet werden kann, wenn kein Anfangswert vorhanden ist und die Liste leer ist.

[Bonus-java8-Stream]: Noch eine Reduzierung

Ich werde den verbleibenden vorstellen.

Das zweite ist das.

<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);

U reduce(U u, ((U, T) -> U) f, ((U, U) -> U) g);    //Vereinfachung

U reduce(U u, ((U, T) -> U) f);                     //Vergessen Sie vorerst das dritte Argument
T reduce(T t, ((T, T) -> T) f);                     //Repost der ersten Reduktion

Wenn Sie das mysteriöse dritte Argument vergessen, ist es dem ersten "Reduzieren" sehr ähnlich.

Dies bedeutet, dass der Anfangswert, auch wenn er sich vom Listentyp unterscheidet, gefaltet werden kann. In anderen Sprachen ist dieses Formular der Standard.

reduce with zero b.png

Wie bei den letzten drei Argumenten berücksichtigt der Java8-Stream die parallele Ausführung. Daher ist eine Methode erforderlich, um die Ergebnisse der geteilten Ausführung zusammenzuführen. Um ehrlich zu sein, möchte ich, dass Sie dies verbergen.

reduce with zero java8 stream.png (Dies ist wirklich ein "Bild", weil ich die interne Verarbeitung nicht richtig gelesen habe)

Es mag einen gewissen Widerstand gegen das 3-Argument geben, aber wenn Sie denken, dass das 3-Argument Rauschen ist, ist es dasselbe wie in anderen Sprachen, daher ist es gut, es zu lernen, ohne es zu vermeiden.

[Bonus-Java8-Stream]: Anwendung von Reduzieren

Wenn Sie die Summe von "[10, 30, 45, 15]" wissen möchten, sollten Sie "Summe" verwenden. Das ist richtig.

"Reduzieren" ist nur dann wertvoll, wenn der Anfangstyp unterschiedlich ist. Wenn Sie für den Anfangswert einen anderen Typ verwenden können, können Sie dies tatsächlich tun.

Sie können beispielsweise schnell schreiben, ob die Liste von "(" und ")" mit "Reduzieren" korrekt geschlossen wurde.

resolve(asList('(', '(', ')', ')'))   // true

resolve(asList('(', '(', ')'))        // false

resolve(asList('(', ')', ')', '('))   // false

private static boolean resolve(List<Character> cs) {
    return cs.stream()
            .reduce(
                    Optional.of(0),
                    (acc, c) -> c == '('
                            ? acc.map(n -> n + 1)
                            : acc.map(n -> n - 1).filter(n -> n >= 0),
                    (acc1, acc2) -> acc1
                            .flatMap(v1 -> acc2.map(v2 -> v1 + v2))
            ).equals(Optional.of(0));
}

Setzen Sie den Anfangswert auf "Optional (0)" und während der Faltung ".map (n + 1)" für "(" Optional (n) "für", ".map für" Optional (n) "für") " Auf (n -1) `setzen. Wenn es jedoch unter "Optional (0)" fällt, ist es "leer". Sobald es "leer" wird, wird es niemals zu "Optional (0)" zurückkehren, selbst wenn Sie "empty.map (n + 1)" ausführen.

Wenn es am Ende nach dem Falten "Optional (0)" ist, bedeutet dies, dass die Anzahl von "(" und ")" gleich ist und es nie zu viel ")" gab.

Das dritte Argument, das zwei "Optional" zusammenführt, kann hinzugefügt werden, indem man nach innen schaut, wenn beide "Optional (n)" sind. Wenn beide ~ ~ sind, ist das flatMap. Es fühlt sich gut an, wenn dies bald herauskommt.

U reduce(U u, ((U, T) -> U) f, ((U, U) -> U) g);    //Erneut veröffentlichen

Lassen Sie uns lernen, während wir einen Blick auf die Form werfen.

[Bonus-Java8-Stream]: Wenn der Anfangswert von Reduzieren verwendet wird

Da Reduzieren auf die Reihenfolge und Richtung der Berechnung achten muss, werde ich ein kurzes Beispiel geben.

Die beiden haben das gleiche Ergebnis.

Stream.of(1, 2, 3).reduce((acc, n) -> acc + n).orElse(0)    // 6
Stream.of(1, 2, 3).reduce(0, (acc, n) -> acc + n)           // 6

Die beiden Ergebnisse sind jedoch unterschiedlich.

Stream.of("1", "ok", "15:10").reduce((acc, s) -> acc + " | " + s).orElse("")    // 1 | ok | 15:10
Stream.of("1", "ok", "15:10").reduce("", (acc, s) -> acc + " | " + s)           //  | 1 | ok | 15:10

Sie können den Unterschied verstehen, indem Sie selbst ein Bild zeichnen.

Gut zu erinnern.

[Bonus-javaslang]: Richtung reduzieren

Nachdem wir nun "Reduzieren" angesprochen haben, werfen wir einen Blick auf Javaslangs "Reduzieren".

List.of("1", "ok", "15:10").reduceRightOption((s, acc) -> acc + " | " + s).getOrElse("");    // 15:10 | ok | 1

Je nach Sprache und Bibliothek ist auch "Reduzieren" verfügbar, das von rechts ausgeklappt wird. (Beachten Sie, dass dies nicht (acc, s) -> ist, sondern (s, acc) ->)

Selbst wenn Sie dies verwenden, unterscheidet sich das Ergebnis häufig von dem von links. Seien Sie also vorsichtig.

Dies ist das Ende von "Reduzieren"!

[Bonus-javaslang]: takeWhile

Einführung von takeWhile, das bei Listenoperationen nützlich ist. Dies wird mit Javaslang eingeführt. (Ich wusste nicht, dass der Java8-Stream kein "takeWhile" hat ...)

Lassen Sie uns die Zeile "label: millisec" des ersten Themas in der Reihenfolge vom frühesten nur dort setzen, wo es weniger als 30 ist.

lines
    .filter(line -> line.contains(":"))
    .map(line -> Integer.valueOf(line.split(":")[1]))
    .sorted()
    .takeWhile(n -> n < 30);                           // [10, 15]

takeWhile ist wie" von Anfang an nur dann aufnehmen, wenn bestimmte Bedingungen erfüllt sind ". Ich benutze es oft mit dropWhile, also ist es gut, sich auch daran zu erinnern.

take while.png

[Bonus-Javaslang]: Reißverschluss

Zum Schluss werde ich noch einen vorstellen, "zip", den ich unerwartet oft benutze. Dies wird mit Javaslang eingeführt.

Es ist, als würde man denselben Teil von zwei Listen koppeln. Es ist möglicherweise einfacher zu verstehen, wenn Sie glauben, dass es sich wie ein Reißverschluss anfühlt.

List.of(1, 2, 3)
    .zip(List.of('a', 'b', 'c'))    // [(1, a), (2, b), (3, c)]
zip.png ("Zip" kann nur verwendet werden, wenn es einen Typ gibt, der verschiedene Typen wie "Tupel " koppeln kann.)

Anders als wenn Sie "A" und "B" koppeln möchten, wenn Sie beispielsweise die Größe jeder Lücke in der Liste "Ganzzahl" wissen möchten, versuchen Sie "zip", indem Sie dieselbe Liste um eins verschieben. Da ist ein Weg.

List<Integer> times = List.of(10, 15, 35, 60); //Dies[15 - 10, 35 - 15, 60 - 35]Möchte

times
    .zip(times.subSequence(1))
    .map(t -> t._2 - t._1);                    // [5, 20, 25]

Verwenden Sie "Reduzieren", wenn Sie von Anfang an über die Verarbeitung nachdenken? Sie mögen denken, aber wenn Sie ein Bild machen, ist es völlig anders. (Reduzieren berechnet nicht mit dem Nachbarn, sondern berechnet die Summe (oder etwas) bis zu diesem Punkt nacheinander, sodass die Lückenberechnung nicht einfach durchgeführt werden kann.)

zip resolve.png

Wenn Sie in einer Protokolldatei "zip" gut filtern und zuordnen, "zip", den Verarbeitungszeitunterschied für jede Zeile verwenden und "umgekehrte Sortierung und takeWhile" versuchen, werden die Zeilen, die 500 ms oder mehr dauern, in der Reihenfolge ihrer Langsamkeit angezeigt. Du kannst es schaffen.

[Bonus-java8 stream / javaslang]: Vorteile der Karte

Es wird definitiv Gespräche wie "Ich kenne die Vorzüge nicht" und "Ist es nicht in Ordnung für?" Geben, aber natürlich gibt es Vorzüge, die die Lernkosten wert sind.

Es gibt einige, aber ich werde kurz drei auflisten.

1. Sie können die Situation von dem trennen, was Sie tun möchten

Zum Beispiel gibt es eine solche Funktion von "String-> Integer".

private static Integer toIntAndTwice(String s) {
    return Integer.valueOf(s) * 2;
}

Um ehrlich zu sein, schreiben Sie den Code, der diese Funktion auf "wenn es mehrere" Strings "gibt," wenn es höchstens einen "String" gibt "und" wenn es einen "String" gibt, der möglicherweise fehlerhaft ist "anwendet. Werden.

Beispiel "Liste"

List<Integer> result = List.empty();

List<String> org = ...; // List.of(1, 2, 3) or empty

for (String x : org) {
    result.append(toIntAndTwice(x));
}

return result;

Option Beispiel

Option<Integer> result;

Option<String> org = ...; // Option.of(1) or empty

if (org.isEmpty()) {
    result = Option.none();
} else {
    result = Option.of(toIntAndTwice(org.get()));
}

return result;

try Beispiel

Integer result;

String org = ...; // "1" or "x"

try {
    result = toIntAndTwice(org);
} catch (Throwable t) {
    result = null;
}

return result;

Sie müssen einen völlig anderen Code schreiben, um in einer bestimmten Situation "toIntAndTwice" auf "String" anzuwenden.

Wenn Sie dies mit map schreiben, wird es so sein.

Beispiel "Liste"

List<String> org = ...;
List<Integer> mapped = org.map(JSMain::toIntAndTwice);
return mapped;

Option Beispiel

Option<String> org = ...;
Option<Integer> mapped = org.map(JSMain::toIntAndTwice);
return mapped;

Try Beispiel

Try<String> org = ...;
Try<Integer> mapped = org.map(JSMain::toIntAndTwice);
return mapped;

Es sieht genauso aus! Dies liegt daran, dass "die Regeln von" Liste "und" Option "in einer bestimmten Situation" und "was Sie tatsächlich tun möchten (" toIntAndTwice ")" getrennt sind und erstere von der Sprache gefolgt wird.

Übrigens, wenn der Code bisher ähnlich ist, habe ich das Gefühl, dass er allgemeiner gemacht werden kann, oder? Da "List" und "Option" von Javaslang von "Value" erben, können Sie dies auch tun.

Wenn Sie einen solchen Wert -> Wert definieren,

private static Value<Integer> mapAnyType(Value<String> org) {
    return org.map(JSMain::toIntAndTwice);
}

Es funktioniert, ob das Argument "Liste" oder "Option" ist!

Beispiel "Liste"

Value<Integer> m1 = mapAnyType(List.of("1", "2", "3")); // List(2, 4, 6)

Option Beispiel

Value<Integer> m2 = mapAnyType(Option.none());          // None

Try Beispiel

Value<Integer> m3 = mapAnyType(Try.of(() -> "x"));      // Failure(java.lang.NumberFormatException: For input string: "x")

In diesem Fall kann derselbe Code unterschiedliche Situationen behandeln. Bereiten Sie beispielsweise einen "Stornierungsprozess für Zahlungsoptionen", eine Funktion zum gleichzeitigen Abbrechen ("Liste") und eine Funktion zum Abbrechen vor, wenn Sie ("Option") haben. ")" Und "Die Funktion zum Abbrechen, weil Sie sie haben sollten ( Try) "kann sofort realisiert werden.

Ich denke, der größte Vorteil ist die Trennung von "Situation" und "Verarbeitung".

2. Temporäre Variablen werden nicht angezeigt

Legacy-Code, den jeder liebt. Das ist üblich.

//Initialisieren
result = 0;
flag = false;

for (i ...) {
    result = ...;

    //Ist ~ ~ fertig?
    if (i < ...) {
        result = ...;
        flag = true;
    }

    //Wenn ~ ~ dann ende
    if (flag) {
        return result;
    }

    //Dann Schleife mit ~ ~
    for (j ...) {
        result = ...;

        //Wenn ~ ~ dann ende
        if (j < ...) {
            return result;
        }
    }
    //Initialisieren
    flag = false;
}

//Rückkehr
return result;

Das Rückgabeergebnis in diesem Code ist dasselbe wie der Text, aber der Inhalt ist völlig anders. (Vielleicht weiß ich es gar nicht.)

Da die Zeilen einen Kontext enthalten, können Sie nicht nur diese Zeile kopieren und einfügen, und es scheint, dass Sie Blöcke mit Kommentaren erstellen. In Wirklichkeit ist dies jedoch nur ein großer Block.

Wenn dies wie der obige Code aussieht, arbeiten alle drei Zeilen des Arguments unabhängig voneinander, und es gibt keine in Bearbeitung befindlichen Variablen im Methodenbereich, die nicht "return" sein sollten. (Da es ein ; gibt, ist dieser Code eine Zeile. Daher kann es keinen Lückenzustand geben.)

return cs.stream()
        .reduce(
                Optional.of(0),
                (acc, c) -> c == '(' ? acc.map(n -> n + 1) : acc.map(n -> n - 1).filter(n -> n >= 0),
                (acc1, acc2) -> acc1.flatMap(v1 -> acc2.map(v2 -> v1 + v2))
        ).equals(Optional.of(0));

Ich denke, dass dies überwiegend wiederverwendbarer und von höherer Qualität ist. (Wenn Sie dies mit gemeinsam genutztem Code tun, sollten Sie natürlich etwas vorsichtiger sein. Das zweite Argument sollte richtig benannt und der Testcode leicht geschrieben sein. Das dritte Argument sollte "ReduceUtil :: mergeOptional" sein. Effektives Java Ich denke, die 3. Ausgabe hat das auch gesagt.)

3. Nutzen Sie die Erfahrung einer anderen Sprache

Ich werde als nächstes auf die Details eingehen, aber je mehr Sie die Idee selbst kennen, desto besser wird sie auf den ersten Blick, es sei denn, es handelt sich um eine spezielle Sprache.

Wenn Sie Java8-Stream lernen und zu Ruby wechseln, können Sie die Liste sofort bearbeiten. Selbst wenn Sie mit Java8 noch nicht vertraut sind und mit Python vertraut sind, können Sie Streams erstellen.

[Bonus]: Wordbook

Wie in den Last-Minute-Vorteilen erwähnt, verfügen die meisten Sprachen über "Map, Filter, Reduce".

Wenn Sie eine Sprache beibehalten müssen, die Sie bei der Arbeit nicht so schnell kennen, oder wenn Sie einige Änderungen an den von Ihnen aufgenommenen Werkzeugen vornehmen möchten, ist es in Ordnung, wenn Sie die Wörter kennen und Bilder verarbeiten. Am Ende werde ich mit einer Zusammenfassung abschließen, wie dieselbe Verarbeitung in der Sprache durchgeführt wird, die Sie häufig hören.

(Der Teil mit (*) fühlt sich so an, als könnten Sie etwas Ähnliches tun, wenn Sie es gut verwenden.)

lang map filter reduce(zero / left)
reduce(head / left)
reduce(zero / right)
reduce(head / right)
take while zip
java map filter reduce
reduce
-
-
- -
groovy collect findAll inject
inject
-
-
takeWhile transpose (*)
scala map filter reduceLeft / reduceLeftOption
foldLeft
reduceRight / reduceRightOption
foldRight
takeWhile zip
python map filter reduce
-
-
-
itertools.takewhile zip
php array_map array_filter array_reduce
array_reduce
-
-
- array_map (*)
ruby map / collect select reduce / inject
reduce / inject
-
-
take_while zip
js map filter reduce
reduce
reduceRight
reduceRight
- -
haskell map filter foldl
foldl1
foldr
foldr1
takeWhile zip

Wenn Sie sich an die Wörter um "Map / Collect", "Filter", "Reduce / Fold / Inject" erinnern, funktionieren die meisten Sprachen.

"Map vs Collect" und "Reduce vs Inject" können interessant sein.

Ende

Wenn jemand so weit gelesen hat, danke.

Es war gut, dass der Artikel an dem Tag pünktlich war, an dem ich ihn deklarierte. Das ist es.

Recommended Posts

Listenverarbeitung zum Verstehen mit Bildern --java8 stream / javaslang --bonus
Listenverarbeitung zum Verstehen mit Bildern --java8 stream / javaslang-
[java8] Um die Stream-API zu verstehen
Java8-Listenkonvertierung mit Stream Map
[Java] Stream-Verarbeitung
Beispielcode zum Konvertieren von List in List <String> in Java Stream
Java zum Spielen mit Function
So behandeln Sie Ausnahmen mit Java 8 Stream oder Optional kühl
Ich möchte eine Liste mit Kotlin und Java erstellen!
Stellen Sie mit Java eine Verbindung zur Datenbank her
Stellen Sie mit Java eine Verbindung zu MySQL 8 her
[Java] Einführung in die Stream-API
Java-Thread locker zu verstehen
Konvertieren Sie ein zweidimensionales Array mit der Java 8 Stream-API in das CSV-Format
[Java 8] Doppelte Löschung (& doppelte Überprüfung) mit Stream
[Java] Mit Arrays.asList () zu beachtende Punkte
[Einführung in Java] Informationen zur Stream-API
Delegieren Sie Java-Verarbeitung an JavaScript
Wagen Sie es, Kaggle mit Java herauszufordern (1)
[Java] Elementexistenzprüfung mit Stream
[Verarbeitung × Java] Verwendung von Variablen
Ich habe versucht, mit Java zu interagieren
[Java] Konvertiere 1 in N Liste in Karte
[Java] Verwendung von List [ArrayList]
Serververarbeitung mit Java (Einführung Teil.1)
Überraschend tiefe Java-Liste Inversion-Stream-Verarbeitung
Grundlegender Verarbeitungsablauf von Java Stream
Java, Arrays für Anfänger
Java 8 ~ Stream API ~ startet jetzt
[Java] Konvertierung von Array zu Liste
[Verarbeitung × Java] Verwendung von Arrays
Java-Array / Liste / Stream gegenseitige Konvertierungsliste
[Java] [ibatis] So erhalten Sie 1-zu-N-Beziehungsdatensätze mit List <Map <>>
Ich möchte Group By-Verarbeitung mit Stream durchführen (Group-by-Count, Group-by-Sum, Group-by-Max).
Java8 / 9-Anfänger: Streamen Sie API-Suchtpunkte und wie Sie damit umgehen
[Java] Listen- / Kartenelemente mit Iterator abrufen
Datenverarbeitung mit der Stream-API von Java 8
So kompilieren Sie Java mit VsCode & Ant
[Java] Fassen Sie zusammen, wie Sie mit der Methode equals vergleichen können
Einführung in Algorithmen mit Java-Suche (Tiefenprioritätssuche)
[Verarbeitung × Java] Verwendung der Schleife
Ändern Sie die Liste <Optional <T >> in Java in Optional <Liste <T >>
[Java] Map # Merge ist schwer zu verstehen.
[Verarbeitung × Java] Verwendung der Klasse
[Verarbeitung × Java] Verwendung der Funktion
Einfach mit regulären Java-Ausdrücken zu stolpern
Einführung in Algorithmen mit Java --Search (Breitenprioritätssuche)
[Java] Verschiedene Methoden, um den in List gespeicherten Wert durch iterative Verarbeitung zu ermitteln