Aleph
Aleph

Reputation: 76

Get a rate by month by applying function after groupingBy with Java Stream

I have a Exam table like this:

Exam
student_id | exam_date | status

1            2016-01-01  absence
2            2016-01-28  pass

3            2016-02-03  absence
1            2016-02-08  pass
4            2016-02-22  pass
5            2016-02-27  pass
6            2016-02-28  fail

5            2016-03-01  fail
3            2016-03-24  fail
7            2016-03-30  pass

This should be my 'Map of Integer, Decimal' result after stream:

Month, Rate

[1, 1.00]
[2, 0.75]
[3, 0.33]

Rate = pass / pass + fail

For now I have this following code working, but I have to change Collectors.counting() with the Rate formula:

repository.findAllLastYearExames()
.stream().collect(Collectors.groupingBy(Exam::getMonthExam, Collectors.counting()));

Upvotes: 2

Views: 262

Answers (1)

Alexis C.
Alexis C.

Reputation: 93872

One way to do that is to filter in first place the exams where the status is not pass or fail and then use averagingDouble where you will return 1 for an exam that passes and 0 for an exam that fails to compute the average.

import static java.util.stream.Collectors.averagingDouble;
import static java.util.stream.Collectors.groupingBy;

...

Map<Integer, Double> map =
     examList.stream()
             //or filter to have a status that is either PASS or FAIL instead
             .filter(e -> e.getStatus() != Exam.Status.ABSENCE)
             .collect(groupingBy(Exam::getMonthExam, 
                                 averagingDouble(e -> e.getStatus() == Exam.Status.PASS ? 1 : 0)));

Upvotes: 1

Related Questions