Home > Net >  Java - Stream API: applying reduce() operation to find the Minimum value that meets the requirements
Java - Stream API: applying reduce() operation to find the Minimum value that meets the requirements

Time:08-28

Small question regarding Java and its Stream API, especially the reduce() operation.

I have as input some Stream of integers.

The integers go from -1 inclusive, to a positive integer. In the mathematical notation, it would be [-1,n].

Note that the smallest possible number is -1 (minus 1). It cannot be -2, -3, etc., the smallest is -1.

I would like to write a reduce function which does:

Case A - if the stream contains numbers from 0 to n, basically, there is no -1 in the stream, return the minimum number of the stream.

Stream<Integer> casea = Stream.of(2, 0, 4);

For above case A example, to return 0.

Case B - if the stream contains only -1, there is nothing else other than -1, return -1.

Stream<Integer> caseb = Stream.of(-1, -1, -1);

For above case B example, to return -1.

Case C - if the stream contains any -1, and any non -1, return the minimum number that is not -1.

Stream<Integer> casec = Stream.of(-1, 2, 5);

For above case C example, return 2 (and not -1).

I am having trouble crafting this reduce function.

What I have tried:

So far, I tried:

.reduce(Integer.MAX_VALUE, Integer::min);

Unfortunately, it is not correct. It is returning the correct result for case a and b.

However, it will return -1 for the case c, where I would like to return the smallest non -1 integer, since it has something other than -1 in the stream.

How can I apply reduce operation to meat the requirements?

CodePudding user response:

To find the smallest element that is different from -1, firstly, apply filter() to retain only non-minus-one elements in the stream and then apply min().

As a default value, which would be returned if the stream appears to be empty, provide -1.

public static int getSmallestNonMinusOne(List<Integer> list) {
    
    return list.stream()
        .mapToInt(Integer::intValue)
        .filter(i -> i != -1)
        .min()
        .orElse(-1);
}

Alternatively, if you want to use reduce() you can re-write the code like this:

public static int getSmallestNonMinusOne(List<Integer> list) {
    
    return list.stream()
        .mapToInt(Integer::intValue)
        .filter(i -> i != -1)
        .reduce(Integer::min)
        .orElse(-1);
}

Note: that min is basically a specialized form of reduction, and from the perspective of readability the first version is preferred one.

main()

public static void main(String[] args) {
    System.out.println(getSmallestNonMinusOne(List.of(-1, 0, 8)));
    System.out.println(getSmallestNonMinusOne(List.of(-1, -1, -1)));
    System.out.println(getSmallestNonMinusOne(List.of(-1, 2, 5)));
    System.out.println(getSmallestNonMinusOne(List.of()));
}

Output:

0    // -1, 0, 8
-1   // only -1 elements in the source
2    // -1, 2, 5
-1   // source is empty

CodePudding user response:

If you want to specifically use the reduce operator:

numbers.stream().reduce(-1, (submin, element) ->
    (submin == -1 && element != -1) 
    ? element // here, I have seen the first non-minus-one number
    : element != -1 ? Math.min(submin, element) : submin;  // here, I would keep updating the minimum without considering any minus ones 

It starts with a minus one as the minimum, changes the minimum if it encounters a non-minus-one element, and keeps updating the minimum the normal way, ignoring any next -1s too.

  • Related