Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Java 8 stream methods to get the last max value

Given a list of items with properties, I am trying to get the last item to appear with a maximum value of said property.

For example, for the following list of objects:

t  i
A: 3
D: 7 *
F: 4
C: 5
X: 7 *
M: 6

I can get one of the Things with the highest i:

Thing t = items.stream()
        .max(Comparator.comparingLong(Thing::getI))
        .orElse(null);

However, this will get me Thing t = D. Is there a clean and elegant way of getting the last item, i.e. X in this case?

One possible solution is using the reduce function. However, the property is calculated on the fly and it would look more like:

Thing t = items.stream()
        .reduce((left, right) -> {
            long leftValue = valueFunction.apply(left);
            long rightValue = valueFunction.apply(right);
            return leftValue > rightValue ? left : right;
        })
        .orElse(null);

The valueFunction now needs to be called nearly twice as often.

Other obvious roundabout solutions are:

  1. Store the object in a Tuple with its index
  2. Store the object in a Tuple with its computed value
  3. Reverse the list beforehand
  4. Don't use Streams
like image 450
Druckles Avatar asked Feb 05 '19 13:02

Druckles


People also ask

How do you find the maximum value of a stream?

Stream. max() returns the maximum element of the stream based on the provided Comparator. A Comparator is a comparison function, which imposes a total ordering on some collection of objects. max() is a terminal operation which combines stream elements and returns a summary result.

How do you find the maximum and minimum of a stream?

To get max or min date from a stream of dates, you can use Comparator. comparing( LocalDate::toEpochDay ) Comparator. The toEpochDay() function returns the count of days since epoch i.e. 1970-01-01.

How can we fetch the maximum salary of employee using inbuilt method present in java8?

maxBy() method finds the Employee with the maximum salary and prints it as “ Employee Name:Tom Jones Age:45 Salary:15000.0 ”. Employee details are printed as per the formatting defined in the overridden toString() method in the Employee POJO class.


2 Answers

Remove the equals option (don't return 0 if the compared numbers are equal, return -1 instead) from the comparator (ie. write your own comparator that doesn't include an equals option):

Thing t = items.stream()
        .max((a, b) -> a.getI() > b.getI() ? 1 : -1)
        .orElse(null);
like image 58
jvdmr Avatar answered Oct 20 '22 06:10

jvdmr


Conceptually, you seem to be possibly looking for something like thenComparing using the index of the elements in the list:

Thing t = items.stream()
        .max(Comparator.comparingLong(Thing::getI).thenComparing(items::indexOf))
        .orElse(null);
like image 33
Naman Avatar answered Oct 20 '22 04:10

Naman