How to stop a reduce operation mid way based on some condition?

1.2k views Asked by At

How to stop a reduce operation mid way based on some condition?

For example, how can I find an index of maximum value in a list of integers before hitting 0. So in code below, processing list1 should return 4 (5th element), while processing list2 should return 1 (2nd element, because 8 it is the max value in 5, 8, 3 which are the values before 0).

    List<Integer> list1 = Arrays.asList(5, 8, 3, 2, 10, 7);
    List<Integer> list2 = Arrays.asList(5, 8, 3, 0, 2, 10, 7);
    // This will work for list1 but not for list2
    IntStream.range(0, list1.size())
            .reduce((a, b) -> list1.get(a) < list1.get(b) ? b : a)
            .ifPresent(ix -> System.out.println("Index: " + ix));
1

There are 1 answers

0
Holger On BEST ANSWER

Reduction is meant to work on an entire set of values without specifying in which order the actual processing is going to happen. In this regard, there is no “stopping at point x” possible as that would imply an order of processing.

So the simple answer is, reduce does not support it, thus, if you want to limit the search range, do the limiting first:

List<Integer> list2 = Arrays.asList(5, 8, 3, 0, 2, 10, 7);
int limit=list2.indexOf(0);
IntStream.range(0, limit>=0? limit: list2.size())
        .reduce((a, b) -> list2.get(a) < list2.get(b) ? b : a)
        .ifPresent(ix -> System.out.println("Index: " + ix));

Note that you can implement a new kind of Stream that ends on a certain condition using the lowlevel Spliterator interface as described in this answer but I don’t think that this effort will pay off.

Starting with Java 9, you can use:

IntStream.range(0, list2.size())
    .takeWhile(ix -> list2.get(ix) != 0)
    .reduce((a, b) -> list2.get(a) < list2.get(b) ? b : a)
    .ifPresent(ix -> System.out.println("Index: " + ix));

takeWhile depends on the encounter order of the preceding stream. Since IntStream.range produces an ordered stream, it is guaranteed that only the elements before the first mismatching element in encounter order will be used by the subsequent reduction.