ptt
ptt

Reputation: 123

How to group by an attribute and get a map of max values?

I have the following class:

public class StudentGrade {
   int studentId;
   double value;
   Date date;
   ...
}

I would like to get the max grade by student as a map (studentId -> StudentGrade)

public Map<Integer, StudentGrade> getMaxGradeByStudent(List<StudentGrade> grades) {
    Map<Integer, Optional<StudentGrade>> maxGrades = grades.stream().collect(
        Collectors.groupingBy(
            StudentGrade::getStudentId,
            Collectors.maxBy(Comparator.comparing(StudentGrade::getValue)))
    );
    Map<Integer, StudentGrade> finalGrades = new HashMap<>();
    maxGrades.entrySet().forEach(entry -> {
        entry.getValue().ifPresent(value -> finalGrades.put(entry.getKey(), value));
    })
}

Is there a better way to do this? I would like to avoid having to initialize a new Hashmap and use streams for everything.

Upvotes: 1

Views: 493

Answers (2)

You can use this if you'd like to avoid streams

public Map<Integer, StudentGrade> getMaxGradeByStudent(List<StudentGrade> grades) {
    Map<Integer, StudentGrade> studentIdToMaxGrade = new HashMap<>();
    for (StudentGrade grade : grades) {
        studentIdToMaxGrade.merge(
                grade.getStudentId(),
                grade,
                BinaryOperator.maxBy(Comparator.comparing(StudentGrade::getValue))
        );
    }
    return studentIdToMaxGrade;
}

Upvotes: 0

Youcef LAIDANI
Youcef LAIDANI

Reputation: 59978

You can use toMap instead of groupingBy, and BinaryOperator instead of Collectors.maxBy, like:

public Map<Integer, StudentGrade> getMaxGradeByStudent(List<StudentGrade> grades) {
    return grades.stream()
            .collect(Collectors.toMap(StudentGrade::getStudentId,
                   x -> x, // Or Function.identity(),
                   BinaryOperator.maxBy(Comparator.comparing(StudentGrade::getValue))));
}

Upvotes: 4

Related Questions