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 -1
s too.