Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert nested loops to nested Streams? [duplicate]

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();
like image 222
MLeiria Avatar asked Dec 13 '22 21:12

MLeiria


2 Answers

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();
like image 166
Eugene Avatar answered Jan 15 '23 06:01

Eugene


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();
like image 42
Grzegorz Piwowarek Avatar answered Jan 15 '23 05:01

Grzegorz Piwowarek