Skip to content
Advertisement

Java streams – Get max two objects depending on condition

Relatively new to java streams and I have encountered an issue which I could not find a solution for.

I have A list of 10 objects and filtered them to return 4 objects.

List<MyObject> objects.stream()
                      .filter(x -> x.getFlag == 1)
                      .filter(x -> x.amount != null)
                      .collect(Collectors.toList());

this returns 4 objects:

OBJECT 1: {stageNumber = 2, stageToCalc = 1}
OBJECT 2: {stageNumber = 5, stageToCalc = 1}
OBJECT 3: {stageNumber = 9, stageToCalc = 7}
OBJECT 4: {stageNumber = 10, stageToCalc = 7}

So basically what I am trying to do is take stages that have the same value of stageToCalc and find the maximium stageNumber.

E.G: object 3 and object 4 have the same stageToCalc = 7, maximum value according to stage number should return Object 4: {stageNumber = 10, stageToCalc = 7} which is the higher value.

however, my issue comes when I need to get 2 (or more since it might be dynamic). in this case :

it should return object 2 and Object 4.

I have tried using:

objects.stream()
       .collect(groupingBy(Function.identity(), TreeMap::new, toList())
       .lastEntry()
       .getValue()
       .forEach(System.out::println)

This will just result in a classCastException, and if I Use .max() it would not compile. I could easy accomplish this in an expensive way with some for loops etc.

however I wonder if there is a way in using just 1 stream iteration.

Hope I am clear on this question. Still new and learning.

THANKS.

Advertisement

Answer

You can use Collectors.groupingBy() with a downstream Collectors.maxBy() to get the appropriate objects (With Collectors.collectAndThen() to pull them out of the Optional values returned by maxBy()):

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class Demo {
    private record MyObject(int stageNumber, int stageToCalc) {}


    public static void main(String[] args) {
        List<MyObject> objects = List.of(new MyObject(2, 1), new MyObject(5, 1), new MyObject(9, 7), new MyObject(10, 7));;

        List<MyObject>  maximums =
            new ArrayList<>(objects.stream()
                            .collect(Collectors.groupingBy(MyObject::stageToCalc,
                                                           Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(MyObject::stageNumber)),
                                                                                        Optional::orElseThrow)))
                            .values());
    System.out.println(maximums);
    }
}

will print out

[MyObject[stageNumber=5, stageToCalc=1], MyObject[stageNumber=10, stageToCalc=7]]
User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement