4

Let's say I have an int array and I want to find all pairs that sum to zero. In the old days I would do something like this:

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

Now I'm having some trouble converting this to streams.

I tried the following approach but I get a 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();
Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
MLeiria
  • 633
  • 1
  • 9
  • 22

2 Answers2

7

change stream2.filter to Arrays.stream(a) - the Stream would be closed the second time you would try to process it.

But you are not counting correctly anyway, it should be:

 IntStream.range(0, a.length)
          .flatMap(x -> Arrays.stream(a).skip(x + 1).filter(j -> j + a[x] == 0))
          .count();
Eugene
  • 117,005
  • 15
  • 201
  • 306
5

Streams are non-reusable so you can't define them once and keep reusing. This is why storing them in variables is considered a bad practice.

You need to create them on the spot:

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

Also, in order to fully reflect the provided implementation and avoid duplicates, you would need to skip some elements at the beginning of each nested Stream:

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

If you want to extract them to variables, you would need to use a Supplier which will serve as a factory for our Streams. Each get call creates a new Stream instance:

final Supplier<IntStream> s = () -> Arrays.stream(a);
long res = s.get()
  .flatMap(i -> s.get().filter(j -> (j + i == 0)))
  .count();
Grzegorz Piwowarek
  • 13,172
  • 8
  • 62
  • 93
  • thanks. It does the trick with the difference that the stream approach counts repeatedly. In the nested for, the inside loop is one step ahead the outer loop, so it does't repeat the count. For instance if `int[] a = new int[]{1,2,3,4,-3,5,-5};` the nested for gives a result of 2 which is correct because there are only two elements (3, -3) and (5, -5) but the stream gives a result of 4 – MLeiria Aug 03 '17 at 12:29
  • @MLeiria i will update the answer – Grzegorz Piwowarek Aug 03 '17 at 12:33