1

I'm planning to leverage the benefits of using parallel streams in my program and I want to replace a loop like this:

    for (int gridY = gridYFrom; gridY <= gridYTo; gridY++) {
        for (int gridX = gridXFrom; gridX <= gridXTo; gridX++) {
            coordinates.add(Coordinate.from(gridX, gridY));
        }
    }

with something like this:

    IntStream.rangeClosed(gridYFrom, gridYTo).parallel().map(y -> 
        IntStream.rangeClosed(gridXFrom, gridXTo).mapToObj(x -> {
            return Coordinate.from(x, y);
        }
    )).collect(Collectors.toSet());

My problem is that here I get a cyclic inference error. I understand that I am supposed to return an int from the inner map to be compatible with the outer one but I want to return a Coordinate object (thus the mapToObj call). Is it possible to do so using collect and without using a forEach construct?

2 Answers 2

4

What you want to do is these things:

First of all, when you call map on an IntStream, it still returns an IntStream, which isn't what you want. Instead, also use mapToObj for the outer loop.

Second of all, the inner loop returns an incomplete Stream<Coordinate>, which I assume is also not what you want. So, you'll want to call .collect(Collectors.toSet()) on that as well.

Finally, you'll want to flatMap the Stream<Set<Coordinate>> into a single Stream<Coordinate>, and you can do that by using

stream.flatmap(Set::stream);

This all boils down to

IntStream.rangeClosed(0, 10).parallel().mapToObj(y ->
    IntStream.rangeClosed(0, 20).mapToObj(x -> 
        Coordinate.from(x,y)).collect(Collectors.toSet())
).flatMap(Set::stream).collect(Collectors.toSet());

EDIT: Actually, forget the inner collect. Just flatmap to Stream::sequential.

You'll end up with

IntStream.rangeClosed(0, 10).parallel().mapToObj(y -> 
    IntStream.rangeClosed(0, 20).mapToObj(x -> 
        Coordinate.from(x, y))).flatMap(Stream::sequential).collect(Collectors.toSet())
Sign up to request clarification or add additional context in comments.

3 Comments

Great, thanks! I figured out that I need to collect twice but the other mapToObj was still a problem.
Please check my edit. I completely forgot about Stream::sequential.
Why do use Stream::sequential as function to flat map the inner streams? Just use flatMap(s -> s).
2

You don't need to collect twice. The problem is that IntStream isn't like any other stream in java, unfortunately. So, you have to convert it into a normal stream first, then you can do flatMap:

IntStream.rangeClosed(gridYFrom, gridYTo)
   .mapToObj( y -> Integer.valueOf(y) )
   .flatMap( y -> 
      IntStream.rangeClosed(gridXFrom, gridXTo)
         .mapToObj(x ->  Coordinate.from(x,y))
   )
   .collect(Collectors.toSet())

1 Comment

You can use .boxed() instead of .mapToObj( y -> Integer.valueOf(y) )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.