Портирование вложенного цикла по одному и тому же списку в поток Java - PullRequest
0 голосов
/ 25 мая 2018

В попытке изучить Java, я работаю над решением проблемы Project Euler 23 , где мне нужно найти сумму всех натуральных чисел, которая не может быть записана как сумма двухобильные числа.Мое решение использует потоки Java 8.Я не буду портить его, публикуя здесь фактический ответ, но я буду обсуждать свою стратегию, чтобы найти решение.

Сначала я создаю список чисел, используя IntStream:

List<Integer> abundants = IntStream.range(1, EULER23_MAX)
        .filter(i -> Util.sumOfDivisors(i) > i)
        .boxed()
        .collect(Collectors.toList());

Затем на основе списка я создаю набор сумм из 2 чисел чисел, меньших, чем максимум:

private Set<Integer> calcSumsOfTwoAbundants(List<Integer> abundants) {
    Set<Integer> iset = new HashSet<>();
    Integer[] arr = abundants.toArray(new Integer[abundants.size()]);

    for (int i = 0; i < arr.length - 2; i++) {
        for (int j = i; j < arr.length - 1; j++) {
            int sum = arr[i] + arr[j];
            if (sum <= EULER23_MAX) {
                iset.add(sum);
            }
        }
    }

    return iset;
}

Наконец, я генерирую другой поток, который отфильтровывает все числа, меньшие, чем максимум, которыеприсутствует в наборе сумм двух чисел, и я суммирую это, чтобы получить результат.

result = IntStream.range(1, EULER23_MAX)
        .filter(x -> !sumsOfTwoAbundants.contains(x))
        .sum();

Мои вопросы таковы: Как я могу закодировать логику в calcSumsOfTwoAbundantsиспользовать свободный синтаксис потоков вместо вложенных циклов for?Я пробовал несколько разных вещей, но я продолжаю получать сообщение об ошибке «поток уже закрыт» или совершенно неверный результат.Я также понимаю, что вложенные циклы for, возможно, быстрее, чем использование потоков, но это чисто интеллектуальное упражнение ... вот что я сейчас делаю:

// wrong results
private Set<Integer> calcSumsOfTwoAbundantsAlt(List<Integer> abundants) {
    return abundants.stream()
            .filter(i -> abundants.stream()
                    .anyMatch(j -> (i + j) <= EULER23_MAX))
            .collect(Collectors.toSet());
}

1 Ответ

0 голосов
/ 25 мая 2018

Наиболее прямым эквивалентом будет замена каждого цикла for на IntStream.range и вложение их на flatMap:

Set<Integer> iset = IntStream.range(0, arr.length - 2)
        .flatMap(i -> IntStream.range(i, arr.length - 1)
                .map(j -> arr[i] + arr[j]).filter(s -> s <= EULER23_MAX))
        .boxed().collect(Collectors.toSet());
...