Подтвердить что ты не робот

Как выполнить вложенные операторы if, используя Java 8/lambda?

У меня есть следующий код и вы хотите его реализовать с помощью лямбда-функций только для удовольствия. Можно ли это сделать с помощью основных операций агрегата?

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

Использование лямбда:

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());
4b9b3361

Ответ 1

Существенное замечание здесь заключается в том, что ваша проблема связана с неизоморфным преобразованием: один элемент ввода может отображать нуль, один или два выходных элемента. Всякий раз, когда вы это замечаете, вы должны немедленно начать поиск решения, которое включает flatMap вместо map, потому что это единственный способ добиться такого общего преобразования. В вашем конкретном случае вы можете сначала применить filter для сопоставления элементов с одним нулем, затем flatMap для сопоставления "один-два":

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

Ответ 2

Вы можете объявить тело лямбдой. Например:

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

Может быть

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

Внутри этого тела вы можете создавать вложенные операторы:

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

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

Ответ 3

Используйте flatMap, поскольку вы пытаетесь добавить элементы в конвейер или отображение 1-ко-многим. Карта представляет собой сопоставление от одного к другому.

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

В результате получается тот же список, что и

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

В случае, если вам интересно, какой путь быстрее, метод цикла в 3 раза быстрее, чем использование потоков.

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

Ответ 4

Вы можете сделать это:

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

Ответ 5

Попробуйте использовать 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());

См. http://ideone.com/EOBiEP