3

I am trying to reduce a stream of type Rectangle by doing this:

public static Optional<Rectangle> intersectAll(Stream<Rectangle> rectangles) {

  return rectangles
      .reduce((r1, r2) -> r1.intersection(r2));

The method intersection takes one argument of type Rectangle has return type Optional<Rectangle> and returns a Optional.of(Rectangle) if the two rectangles do intersect, and an Optional.empty() if they do not.

I wish the stream to be reduced such that if one time the r1.intersection(r2) lambda function returns an empty optional, the method intersectAll returns an empty optional, and if r1.intersection(r2) always returns a Rectangle, the output of intersectAll would be the just the reduced Rectangle.

However, as you can probably see, reduce doesn't like this as the intersection method doesn't take in an Optional, so I'm asking if there is a way to 'break out' of the reduce when it hits an empty optional, so I can return an empty optional.

Bdd
  • 51
  • 4
  • 1
    You can do this in a little dirty way: `Optional optRect = rectangles.reduce((r1, r2) -> r1.equals(EMPTY) ? EMPTY : r1.intersection(r2).orElse(EMPTY));` and then `return optRect.isPresent() && optRect.get().equals(EMPTY) ? Optional.empty() : optRect;` where `EMPTY` denotes a special `Rectangle`. – Aniket Sahrawat Apr 15 '21 at 20:36
  • 1
    you can consider a takeWhile with a non-pure predicate that accumulates into a `Optional` outside, but at this point a loop is a better solution. – njzk2 Apr 15 '21 at 20:42

2 Answers2

0

It is not possible to break reduce the terminal operation. But, in some cases, you can achieve the goal with filter, takewhile, findFirst and similar operators.

Akif Hadziabdic
  • 2,692
  • 1
  • 14
  • 25
0

I am sure one can find a solution, but I would like to suggest not do so with a stream.

The intersection of rectangles does not lend itself well to a reduce operation in my opinion. It does not have an identity. You would also need a combiner (see other method signature of the reduce method in Stream class) and implement it appropriately.

An identity is a value so that value op identity == value - try to find such for intersection in general, you won't. Probably that is the reason why you would like to break out. Maybe try to see it as a hint, the path you want to go with this is not beautiful.

As for the combiner you would need to think of how to combine the results - that may not be too hard. Still I feel this is not the way to go.

Try to picture what you are trying to do. The look at the first two lines gives away that it won't fit. And since there is no identity you can use, it does not make sense (Empty intersect Rectangle results in Empty, this is not identity)

R1 intersect R2 intersect R3 intersect R4
   Optional<Ra> intersect R3 intersect R4
                Optional<Rb> intersect R4
                              Optional<Rc>

Would it be ok for you to do this the classical way? You can break out of a loop more easily. It will be more readable too.

Ely
  • 10,860
  • 4
  • 43
  • 64