web-dev-qa-db-fra.com

Comment effectuer des instructions 'if' imbriquées en utilisant Java 8 / lambda?

J'ai le code suivant et je voudrais l'implémenter en utilisant des fonctions lambda juste pour le plaisir. Peut-on le faire en utilisant les opérations d'agrégation de base?

List<Integer> result = new ArrayList<>();

for (int i = 1; i <= 10; i++) {
    if (10 % i == 0) {
        result.add(i);
        if (i != 5) {
            result.add(10 / i);
        }
    }
}

Utilisation de lambda:

List<Integer> result = IntStream.rangeClosed(1, 10)
                                .boxed()
                                .filter(i -> 10 % i == 0)
                                // a map or forEach function here?
                                // .map(return 10 / i -> if i != 5)
                                .collect(Collectors.toList());
21
LuckyGuess

L'observation essentielle ici est que votre problème implique une transformation non isomorphe: un seul élément d'entrée peut correspondre à zéro, un ou deux éléments de sortie. Chaque fois que vous remarquez cela, vous devez immédiatement commencer à rechercher une solution qui implique flatMap au lieu de map car c'est la seule façon de réaliser une telle transformation générale. Dans votre cas particulier, vous pouvez d'abord appliquer filter pour un mappage d'éléments un à zéro, puis flatMap pour un mappage un à deux:

List<Integer> result =
    IntStream.rangeClosed(1, 10)
             .filter(i -> 10 % i == 0)
             .flatMap(i -> i == 5 ? IntStream.of(i) : IntStream.of(i, 10 / i))
             .boxed()
             .collect(toList());
47
Marko Topolnik

Vous pouvez déclarer un corps pour un lambda. Par exemple:

Runnable run = () -> System.out.println("Hey");

Pourrait être

Runnable run = () -> {
    System.out.println("Hey");
};

Dans ce corps, vous pouvez créer des instructions imbriquées:

Runnable run = () -> {
    int num = 5;

    if(num == 5) {
        System.out.println("Hey");
    }
};
5
Vince Emigh

Utilisez flatMap lorsque vous essayez d'ajouter des éléments dans le pipeline ou un mappage 1 à plusieurs. La carte est une cartographie un à un.

ArrayList<Integer> result = (ArrayList<Integer>) IntStream.rangeClosed(1, 10)
                .boxed()
                .filter(i -> 10 % i == 0)
                .flatMap((Integer i) -> {return i!=5 ? Stream.of(i, (10/i)):Stream.of(i);})
                .collect(Collectors.toList());

Il en résulte la même liste que

ArrayList<Integer> result2 = new ArrayList<Integer>();

        for (int i = 1; i <= 10; i++) {
            if (10 % i == 0) {
                result2.add(i);
                if (i != 5) {
                    result2.add(10 / i);
                }
            }
        }

Dans le cas où vous vous demandez quel chemin est plus rapide, la méthode de boucle est ~ 3 fois plus rapide que l'utilisation de flux.

Benchmark                     Mode  Cnt      Score     Error  Units
testStreams.Bench.loops       avgt    5     75.221 ±   0.576  ns/op
testStreams.Bench.streams     avgt    5    257.713 ±  13.125  ns/op
3
Mantis

Tu peux le faire:

List<Integer> result1 = IntStream
    .rangeClosed(1, 10)
    .boxed()
    .filter(i -> 10 % i == 0)
    .map(i -> (i != 5 ? Stream.of(i, 10 / i) : Stream.of(i)))
    .flatMap(Function.identity())
    .collect(Collectors.toList());
1
Mrinal

Essayez d'utiliser flatMap:

List<Integer> result = IntStream.rangeClosed(1, 10)
        .boxed()
        .flatMap((i) -> {
            List<Integer> results = new ArrayList<>();
            if (10 % i == 0) {
                results.add(i);
                if (i != 5) {
                    results.add(10 / i);
                }
            }
            return results.stream();
        })
        .collect(Collectors.toList());

Voir http://ideone.com/EOBiEP

0
Danil Gaponov