Search code examples
javadictionaryjava-streammappingcollectors

How to gather a keyset from multiple maps from a stream that is filtered?


I am trying to learn to work with streams and collectors, I know how to do it with multiple for loops but I want to become a more efficient programmer.

Each project has a map committedHoursPerDay, where the key is the employee and the value is the amount of hours expressed in Integer. I want to loop through all project's committedHoursPerDay maps and filter the maps where the committedHoursPerDay is more than 7(fulltime), and add each of the Employee who works fulltime to the set.

The code that i have written so far is this:

    public Set<Employee> getFulltimeEmployees() {
        // TODO
        Map<Employee,Integer> fulltimeEmployees = projects.stream().filter(p -> p.getCommittedHoursPerDay().entrySet()
                .stream()
                .filter(map -> map.getValue() >= 8)
                .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())));


        return fulltimeEmployees.keySet();
    }

however the filter recognizes the map because I can access the key and values, but in the .collect(Collectors.toMap()) it doesnt recognize the map and only sees it as a lambda argument

enter image description here


Solution

  • There is one to many notion here. You can first flatten the maps using flatMap and then apply filter to the map entries.

    Map<Employee,Integer> fulltimeEmployees = projects.stream()
                    .flatMap(p -> p.getCommittedHoursPerDay()
                            .entrySet()
                            .stream())
                    .filter(mapEntry  -> mapEntry.getValue() >= 8)
                    .collect(Collectors.toMap(mapEntry -> mapEntry.getKey(), mapEntry -> mapEntry.getValue()));
    

    The flatMap step returns a Stream<Map.Entry<Employee, Integer>>. The filter thus operates on a Map.Entry<Employee, Integer>.

    You can also use method reference on the collect step as .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))