Home > front end >  How to group by an attribute and get a map of max values?
How to group by an attribute and get a map of max values?

Time:12-08

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.

CodePudding user response:

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))));
}

CodePudding user response:

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;
}
  • Related