如何将嵌套循环转换为嵌套Streams?

时间:2017-08-03 12:13:52

标签: java arrays java-8 java-stream

假设我有一个int数组,我想找到总和为零的所有对。在过去,我会做这样的事情:

public static int count(int[] a) {
    int cnt = 0;
    int N = a.length;
    for (int i = 0; i < N; i++) {
        for (int j = i + 1; j < N; j++) {

        if (a[i] + a[j] == 0) {
            cnt++;
        }
       }
    }
    return cnt;
    }

现在我在将此转换为流时遇到了一些麻烦。

我尝试了以下方法,但是我收到了IllegalStateException:

final IntStream stream1 = Arrays.stream(a);
final IntStream stream2 = Arrays.stream(a);
long res = stream1.flatMap(i -> stream2.filter(j -> (j + i == 0))).count();

2 个答案:

答案 0 :(得分:5)

stream2.filter更改为Arrays.stream(a) - 第二次尝试处理时,Stream会关闭。

但无论如何你都算不上,应该是:

 IntStream.range(0, a.length)
          .flatMap(x -> Arrays.stream(a).skip(x + 1).filter(j -> j + a[x] == 0))
          .count();

答案 1 :(得分:5)

Streams不可重复使用,因此您无法定义一次并继续重复使用。这就是将它们存储在变量中被认为是一种不好的做法。

您需要在现场创建它们:

long res = Arrays.stream(a)
  .flatMap(i -> Arrays.stream(a).filter(j -> (j + i == 0)))
  .count();

此外,为了完全反映所提供的实现并避免重复,您需要skip每个嵌套Stream开头的一些元素:

long res = IntStream.range(0, a.length)
  .flatMap(i -> Arrays.stream(a).skip(i + 1).filter(j -> (j + a[i] == 0)))
  .count();

如果要将它们提取到变量,则需要使用Supplier作为Streams的工厂。每个get调用都会创建一个新的Stream实例:

final Supplier<IntStream> s = () -> Arrays.stream(a);
long res = s.get()
  .flatMap(i -> s.get().filter(j -> (j + i == 0)))
  .count();