将嵌套for循环在同一列表上移植到Java Stream

时间:2018-05-25 15:28:39

标签: java java-8 java-stream

为了学习Java,我正致力于解决这个问题 Project Euler's problem 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中的逻辑编码为 使用流Fluent语法而不是嵌套的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 :(得分:2)

最直接的等价物是用IntStream.range替换每个for循环并将其与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());