Traitement des listes à comprendre avec des images --java8 stream / javaslang --bonus

Traitement de la liste compris par les images --java8 stream / javaslang- Article supplémentaire!

C'était trop long comme d'habitude, alors je l'ai séparé.

Allons-y grossièrement!

[Bonus-java8 stream]: Autre réduction

Il existe trois définitions de «réduire» dans le flux java8,

Je vais vous présenter les deux autres.

Le premier est celui-ci.

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

Optional<T> reduce(     ((T, T) -> T) f);            //Simplification
         T  reduce(T t, ((T, T) -> T) f);            //Republier la première réduction

La différence d'avant est qu'il n'y a pas de T t et le retour est enveloppé dans ʻOptional`.

Vous pouvez voir pourquoi cela se produit en regardant l'image.

Ceux qui ont le premier T t reduce with zero a.png

Ceux qui n'ont pas T t reduce with head.png

La différence entre la spécification de la valeur initiale par vous-même et l'utilisation de la première comme valeur initiale est la différence de présence ou d'absence de «T t».

Donc, pourquoi le retour est «Optionnel» peut être compris en considérant le cas d'une liste vide.

Si la liste est vide, T t peut être le résultat final reduce with zero empty.png

Rien ne se passe s'il n'y a pas de T t et que la liste est vide reduce with head empty.png

En effet, s'il n'y a pas de valeur initiale et que la liste est vide, un retour ne peut pas être préparé.

[Bonus-java8 stream]: Encore une autre réduction

Je vais vous présenter le reste.

La seconde est la suivante.

<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);    //Simplification

U reduce(U u, ((U, T) -> U) f);                     //Pour le moment, oubliez le troisième argument
T reduce(T t, ((T, T) -> T) f);                     //Republier la première réduction

Si vous oubliez le mystérieux troisième argument, il est très similaire au premier «réduire».

Cela signifie que même si la valeur initiale est différente du type de liste, elle peut être pliée, et dans d'autres langues, cette forme est la norme.

reduce with zero b.png

Ainsi, comme pour les 3 derniers arguments, java8 stream considère l'exécution parallèle, il nécessite donc une méthode pour fusionner les résultats de l'exécution fractionnée. Pour être honnête, je veux que vous cachiez ça.

reduce with zero java8 stream.png (C'est vraiment une "image" car je n'ai pas lu correctement le traitement interne)

Il peut y avoir une certaine résistance à l'argument 3, mais si vous pensez que l'argument 3 est du bruit, c'est le même que les autres langues, il est donc bon de l'apprendre sans l'éviter.

[Bonus-java8 stream]: Application de la réduction

Si vous voulez connaître le total de «[10, 30, 45, 15]», vous devez utiliser «sum».

«réduire» n'a de valeur que si le type initial est différent. Si vous pouvez utiliser un type différent pour la valeur initiale, vous pouvez le faire.

Par exemple, vous pouvez rapidement écrire le processus de vérification si la liste de ( et ) est fermée correctement avec réduire.

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

Définissez la valeur initiale sur ʻOptional (0) , et pendant la convolution, définissez .map (n + 1) sur ʻOptional (n) pour ( et .map sur .map (n) pour) . Réglez sur (n -1) . Cependant, s'il est inférieur à ʻOptional (0) , il sera" vide ". Une fois qu'il devient ʻempty, même si vous faites ʻempty.map (n + 1) , il ne reviendra jamais à ʻOptional (0).

Si c'est ʻOptional (0) à la fin après le pliage, cela signifie que le nombre de (et) est le même, et il n'y en a jamais eu trop) `.

Le troisième argument qui fusionne deux ʻOptionals peut être ajouté en regardant à l'intérieur si les deux sont ʻOptional (n) . Si les deux sont ~ ~, c'est flatMap. Cela fait du bien si cela sort bientôt.

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

Apprenons en regardant le moule.

[Bonus-java8 stream]: lorsque la valeur initiale de reduction est utilisée

Puisque réduire doit faire attention à l'ordre et à la direction du calcul, je vais donner un exemple rapide.

Les deux ont le même résultat.

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

Mais les deux résultats sont différents.

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

Vous pouvez comprendre la différence en dessinant vous-même une image.

Bon à retenir.

[Bonus-javaslang]: réduire la direction

Maintenant que nous avons touché à «réduire», jetons un œil à «réduire» de javaslang.

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

«Réduire», qui se replie par la droite, est également disponible en fonction de la langue et de la bibliothèque. (Notez que ce n'est pas (acc, s) -> mais (s, acc) ->)

Bien sûr, même si vous l'utilisez, le résultat sera souvent différent du cas de gauche, alors soyez prudent.

C'est la fin de «réduire»!

[Bonus-javaslang]: takeWhile

Présentation de takeWhile, qui est utile à retenir par opération de liste. Ceci est introduit en utilisant javaslang. (Je ne savais pas que le flux java8 n'avait pas takeWhile ...)

Mettons la ligne label: millisec du premier sujet, dans l'ordre du plus ancien, uniquement là où elle est inférieure à 30.

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

takeWhile est comme" ne reprendre depuis le début que lorsque certaines conditions sont remplies. " Je l'utilise beaucoup avec dropWhile, donc il est bon de s'en souvenir aussi.

take while.png

[Bonus-javaslang]: zip

Enfin, j'en présenterai un autre, zip, que j'utilise beaucoup de manière inattendue. Ceci est introduit en utilisant javaslang.

C'est comme associer la même partie de deux listes. Cela peut être plus facile à comprendre si vous pensez que cela ressemble à une fermeture à glissière.

List.of(1, 2, 3)
    .zip(List.of('a', 'b', 'c'))    // [(1, a), (2, b), (3, c)]
zip.png (`Zip` ne peut être utilisé que s'il existe un type qui peut associer différents types tels que` Tuple `.)

Autre que lorsque vous voulez coupler ʻA et B, par exemple, si vous voulez connaître la taille de chaque espace dans la liste de ʻInteger, essayez zip en décalant la même liste de un. Il y a un moyen.

List<Integer> times = List.of(10, 15, 35, 60); //cette[15 - 10, 35 - 15, 60 - 35]Vouloir

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

Utilisez-vous «réduire» lorsque vous pensez au traitement depuis le début? Vous pourriez penser, mais si vous faites une image, c'est complètement différent. (Réduire ne calcule pas avec le voisin, mais calcule la somme (ou quelque chose) jusqu'à ce point un par un, de sorte que le calcul de l'écart ne peut pas être simple.)

zip resolve.png

Si vous faites bien filtrer et mapper sur un fichier journal, zip, prenez la différence de temps de traitement pour chaque ligne, et essayez tri inversé et takeWhile, les lignes qui prennent 500 ms ou plus sont affichées par ordre de lenteur Tu peux le faire.

[Bonus-java8 stream / javaslang]: Avantages de la carte

Il y aura certainement des discussions telles que "Je ne connais pas les mérites" et "N'est-ce pas d'accord pour?"

Il y en a quelques-uns, mais j'en énumérerai brièvement trois.

1. Vous pouvez séparer la situation de ce que vous voulez faire

Par exemple, il existe une fonction telle que String-> Integer.

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

Si vous écrivez le code qui applique cette fonction à "quand il y a plusieurs Strings", "quand il y a un maximum d'une" chaîne "", et "quand il y a une" chaîne "qui peut être malformée", Devenir.

Exemple de 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;

Exemple de ʻOption`

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;

Exemple try

Integer result;

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

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

return result;

Vous devez écrire un code complètement différent pour appliquer toIntAndTwice à String dans une situation particulière.

Si vous écrivez ceci avec map, ce sera comme ça.

Exemple de liste

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

Exemple de ʻOption`

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

Exemple Try

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

C'est pareil! Ceci est dû au fait que "les règles de List et de ʻOption dans une situation spécifique" et "ce que vous voulez réellement faire (" toIntAndTwice) "sont séparées, et la première est suivie par la langue.

Au fait, si le code est similaire jusqu'à présent, je pense qu'il peut être rendu plus courant, non? Puisque List et ʻOption de javaslang héritent de Value`, vous pouvez également le faire.

Si vous définissez une telle Valeur <T> -> Valeur <R>,

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

Cela fonctionne que l'argument soit List ou ʻOption`!

Exemple de liste

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

Exemple de ʻOption`

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

Exemple Try

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

Dans ce cas, le même code peut gérer différentes situations, donc par exemple, préparer un processus d'annulation pour les options payantes, et avoir une" fonction pour tout annuler à la fois (Liste)" et une "fonction pour annuler si vous en avez une (ʻOption". ")" Et "La fonction à annuler parce que vous devriez l'avoir ( Try) "peut être réalisée à la fois.

Je pense que le plus grand mérite est la séparation de la «situation» et du «traitement».

2. Les variables temporaires n'apparaissent pas

Un code hérité que tout le monde aime. Ceci est courant.

//Initialisation
result = 0;
flag = false;

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

    //Est-ce que ~ ~ est terminé?
    if (i < ...) {
        result = ...;
        flag = true;
    }

    //Si c'est ~~, ça se termine
    if (flag) {
        return result;
    }

    //Puis boucle avec ~ ~
    for (j ...) {
        result = ...;

        //Si c'est ~~, ça se termine
        if (j < ...) {
            return result;
        }
    }
    //Initialisation
    flag = false;
}

//revenir
return result;

Le return result; dans ce code est le même que le texte, mais le contenu est complètement différent. (Peut-être, je ne sais même pas.)

Puisqu'il y a un contexte dans les lignes, vous ne pouvez pas copier et coller uniquement cette ligne, et il semble que vous créez des blocs avec des commentaires, mais en réalité ce n'est qu'un gros bloc.

Si cela ressemble au code ci-dessus, les trois lignes de l'argument fonctionnent indépendamment et il n'y a pas de variables en cours dans la portée de la méthode qui ne devraient pas être «return». (Puisqu'il y en a un ;, ce code est une ligne. Par conséquent, il ne peut y avoir aucun état d'intervalle.)

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

Je pense que c'est extrêmement réutilisable et de meilleure qualité. (Bien sûr, si vous le faites avec du code partagé, vous devriez être un peu plus prudent. Le deuxième argument doit être nommé correctement et le code de test doit être écrit légèrement. Le troisième argument doit être ReduceUtil :: mergeOptional. Java efficace Je pense que la 3e édition l'a également dit.)

3. Utiliser l'expérience d'une autre langue

Je reviendrai ensuite sur les détails, mais plus vous connaissez l'idée elle-même, mieux ce sera à première vue à moins qu'il ne s'agisse d'un langage spécial.

Si vous apprenez le flux java8 et passez à ruby, vous pourrez utiliser la liste immédiatement, et même si vous êtes nouveau sur java8, si vous êtes expérimenté avec python, vous pourrez diffuser.

[Bonus]: Wordbook

Comme mentionné dans les avantages de dernière minute, la plupart des langues ont mapper, filtrer, réduire.

Lorsque vous devez maintenir une langue que vous ne connaissez pas à la hâte au travail, ou lorsque vous souhaitez apporter des modifications aux outils que vous avez choisis, c'est bien si vous connaissez les mots et le traitement des images. Donc, à la fin, je terminerai par un résumé de la façon de faire le même traitement dans la langue que vous entendez souvent.

(La partie avec (*) donne l'impression que vous pouvez faire quelque chose de similaire si vous l'utilisez bien)

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

Si vous vous souvenez des mots autour de map / collect, filter, reduction / fold / inject, la plupart des langages fonctionneront.

«map vs collect» et «reduction vs inject» peuvent être intéressants à examiner.

fin

Si quelqu'un a lu jusqu'ici, merci.

C'était bien que l'article soit à l'heure le jour où je l'ai déclaré. C'est tout.

Recommended Posts

Traitement des listes à comprendre avec des images --java8 stream / javaslang --bonus
Traitement des listes à comprendre avec des images - java8 stream / javaslang-
[java8] Pour comprendre l'API Stream
Conversion de liste Java8 avec Stream map
[Java] Traitement de flux
Exemple de code pour convertir List en List <String> dans Java Stream
Java pour jouer avec Function
Comment gérer les exceptions froidement avec Java 8 Stream ou en option
Je veux faire une liste avec kotlin et java!
Connectez-vous à DB avec Java
Connectez-vous à MySQL 8 avec Java
[Java] Introduction à l'API Stream
Thread Java pour comprendre vaguement
Convertir un tableau bidimensionnel au format csv avec l'API Java 8 Stream
[Java 8] Suppression en double (et vérification en double) avec Stream
[Java] Points à noter avec Arrays.asList ()
[Introduction à Java] À propos de l'API Stream
Déléguer certains traitements Java à JavaScript
Osez défier Kaggle avec Java (1)
[Java] Vérification de l'existence des éléments avec Stream
[Traitement × Java] Comment utiliser les variables
J'ai essayé d'interagir avec Java
[Java] Convertir 1 en N liste en carte
[Java] Comment utiliser List [ArrayList]
Traitement serveur avec Java (Introduction partie 1)
Traitement de flux d'inversion de liste Java étonnamment profond
Flux de traitement de base de Java Stream
Java, des tableaux pour débuter avec les débutants
Java 8 ~ Stream API ~ pour commencer maintenant
[Java] Conversion d'un tableau à une liste
[Traitement × Java] Comment utiliser les tableaux
Liste de conversion mutuelle de tableau / liste / flux Java
[Java] [ibatis] Comment obtenir des enregistrements de relation 1 à N avec List <Map <>>
Je souhaite effectuer un traitement Group By avec Stream (group-by-count, group-by-sum, group-by-max)
Java8 / 9 Beginners: Streaming API addiction points et comment les gérer
[Java] Obtenir des éléments List / Map avec Iterator
Traitement des données à l'aide de l'API de flux de Java 8
Comment compiler Java avec VsCode & Ant
[Java] Résumez comment comparer avec la méthode equals
Introduction aux algorithmes avec java-Search (recherche prioritaire en profondeur)
[Traitement × Java] Comment utiliser la boucle
Remplacez List <Optional <T >> par Optional <List <T >> en Java
[Java] Map # merge est difficile à comprendre.
[Traitement × Java] Comment utiliser la classe
[Traitement × Java] Comment utiliser la fonction
Facile à parcourir avec les expressions régulières Java
Introduction aux algorithmes avec java --Search (recherche de priorité de largeur)
[Java] Différentes méthodes pour acquérir la valeur stockée dans List par traitement itératif