Report on a multimap by producing a new map of each key mapped to the count of elements in its collection value

久未见 提交于 2021-01-29 02:32:35

问题


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 ,
                ???
            )
        )
;

回答1:


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}



来源:https://stackoverflow.com/questions/65676622/report-on-a-multimap-by-producing-a-new-map-of-each-key-mapped-to-the-count-of-e

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!