通过生成映射到其集合值中元素计数的每个键的新映射来报告多图

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

想象一个 multimap 跟踪人员,每个人都有一个分配任务列表。

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") ) 
    )
;

我如何使用流获取新地图,将每个 Person 映射到一个 Integer,其中包含在分配任务列表中找到的项目数?

如何获得与此硬编码地图等效的结果:

Map< Person , Integer >  personToTaskCount = 
    Map.of(
        new Person( "Alice" ) , 2 , 
        new Person( "Bob" )   , 1 , 
        new Person( "Carol" ) , 3 
    )
;

我一直在尝试排列:

Map < Person, Integer > personToTaskCount = 
        personToTasks.keySet().stream().collect
        (
            Collectors.mapping
            (
                Map.Entry :: getKey ,
                ???
            )
        )
;

您走在正确的轨道上,这是一个可能的解决方案:

Map<Person, Integer> personToTaskCount = personToTasks
    .entrySet()
    .stream()
    .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().size()));

Map#entrySet method returns a Set of the elements in a map, a set of Map.Entry 个对象。 Map.Entry 保存映射中每个条目的键值对。我们可以向该对象询问键和值。

在您的示例中,询问每个 Map.Entry 的值会得到 List< Task >。然后我们可以询问该列表的大小,它包含的元素数量。这个大小数字是我们希望您的新地图的值,Map < Person, Integer >

这里是上面代码的扩展版本,使这些 Map.Entry 对象的作用更加明显。

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(); }
                        )
                );

将结果转储到控制台。

System.out.println( "personToTasks = " + personToTasks );
System.out.println( "personToTaskCount = " + personToTaskCount );

当运行.

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}