Imagine a multimap tracking persons, each of whom has a list of assigned tasks.
Map< Person , List< Task > > personToTasks = Map.of( new Person( "Alice" ) , List.of( new Task( "a1" ), new Task( "a2") ) , new Person( "Bob" ) , List.of( new Task( "b1" ) ) , new Person( "Carol" ) , List.of( new Task( "c1" ), new Task( "c2"), new Task( "c3") ) ) ;
How can I use streams to get a new map, mapping each Person
to an Integer
with the count of items found in their list of assigned tasks?
How to get a result equivalent to this hard-coded map:
Map< Person , Integer > personToTaskCount = Map.of( new Person( "Alice" ) , 2 , new Person( "Bob" ) , 1 , new Person( "Carol" ) , 3 ) ;
I have been trying permutations of:
Map < Person, Integer > personToTaskCount = personToTasks.keySet().stream().collect ( Collectors.mapping ( Map.Entry :: getKey , ??? ) ) ;
Advertisement
Answer
You are on the right track, here’s a possible solution:
Map<Person, Integer> personToTaskCount = personToTasks .entrySet() .stream() .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().size()));
The Map#entrySet
method returns a Set
of the elements in a map, a set of Map.Entry
objects. A Map.Entry
holds the key-value pairing of each entry in the map. We can ask that object for the key and for the value.
In your example case, asking for the value of each Map.Entry
gets us a List< Task >
. We can then interrogate that list for its size, the number of elements it contains. This size number is the value we want for your new map, Map < Person, Integer >
.
Here is an expanded version of the code above, to make more obvious these Map.Entry
objects in action.
Map < Person, List < Task > > personToTasks = Map.of( new Person( "Alice" ) , List.of( new Task( "a1" ) , new Task( "a2" ) ) , new Person( "Bob" ) , List.of( new Task( "b1" ) ) , new Person( "Carol" ) , List.of( new Task( "c1" ) , new Task( "c2" ) , new Task( "c3" ) ) ); Map < Person, Integer > personToTaskCount = personToTasks .entrySet() .stream() .collect( Collectors.toMap( ( Map.Entry < Person, List < Task > > e ) -> { return e.getKey(); } , ( Map.Entry < Person, List < Task > > e ) -> { return e.getValue().size(); } ) );
Dump results to console.
System.out.println( "personToTasks = " + personToTasks ); System.out.println( "personToTaskCount = " + personToTaskCount );
When run.
personToTasks = {Person[name=Alice]=[Task[title=a1], Task[title=a2]], Person[name=Carol]=[Task[title=c1], Task[title=c2], Task[title=c3]], Person[name=Bob]=[Task[title=b1]]}
personToTaskCount = {Person[name=Bob]=1, Person[name=Alice]=2, Person[name=Carol]=3}