Question

This question involves mapping and grouping of elements using java 8 collectors. I've got a list of Patient. Each Patient has a list of departments he had visited. Say I want to count for each departments how many time it had been visited using the new collectors API in java 8, how would I group by the departments list?

Thanks!

NOTE: I know that I can put a counter in each of the departments, this question is solely for the purpose of learning the new java 8 features.

Code:

public class Patient {
    private String id;
    private List<Department> history;
    /* some more getters/setters come here */
}

In my main method I have a list of Patient. I want to know for each Department, how many time it had been visited, without editing the Department class (or extending or decorating it).

I think I have to take a stream of patients and map them to a map of dept->count (how many times each patient visited which dept.). Having a stream of these maps - I have no idea what to do to group these maps and count them.

Was it helpful?

Solution

First, I'll assume that if a Patient has visited a Department more than once, that Department will appear in the Patient's history list more than once.

If that's the case, then we can simply take our Stream of Patients and flatMap it to a Stream of Departments, where the occurrence of a Department indicates one visit from a Patient.

Then we can pass this to the groupingBy collector. We want to classify by Department itself, so the classifier function is the identity function.

For the value, we want to put a 1 as the value if an entry for the Department isn't present yet, but we want to add 1 to the existing value if an entry is present. There's a collector called counting() that does this for us already, so we just pass it as a downstream collector to groupingBy().

The resulting code is as follows:

import static java.util.stream.Collectors.*;

List<Patient> patients = ... ;

Map<Department, Long> frequency =
    patients.stream()
        .flatMap(p -> p.getHistory().stream())
        .collect(groupingBy(d -> d, counting()));

Note that if a Department hasn't been visited, it will simply be absent from the map. If you have a list of departments, you can fill in the zero values like this:

departments.forEach(d -> frequency.putIfAbsent(d, 0L));

or if you want to fill in the zero on the get side,

long numVisits = frequency.getOrDefault(dept, 0L);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top