Small question regarding Java and its Stream API, especially the reduce()
function please.
I have as input some Stream of integers.
The integers goes from -1 included, to a positive integer.
The mathematical notation is I think [-1 .. n], it is important the smallest number possible 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 number 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 example case a, 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 example case b, 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 example case b, to 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.
May I ask what is the correct reduce function please?
Thank you
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.