如何对 Stream 的元素进行分组,以便根据其属性选择单个元素

How to group element of the Stream in order to pick a single element based on its poperties

使用 Java 8 个流,我想找到一个 演员 一年 中出演最多电影的人].

电影列表:

List<Movie> movies= [

Movie{name="The Avengers",year="2011",actorList=["Tom","Chris","Robert"]},
Movie{name="Sherlock Holmes",year="2011",actorList=["Robert","Harris","Murphy"]},
Movie{name="Spiderman",year="2002",actorList=["Tobey","William","Kirsten"]},
...

]

电影宝珠:

class Movie{
   String name; 
   String year; 
   List<String> actorList; 
}

预期输出:

[, 演员(一年内出演的电影数量上限 ), 计数(最多电影)]

["2011", "Robert", 2 ]

为此,您可以按 年份 演员姓名 电影 进行分组创建嵌套地图。然后处理它的条目。

可以用Collectors.groupingBy()来完成。您需要将提取 的函数 (Movie::getYear) 作为第一个参数传递,这将是地图的键。

作为 groupingBy 的下游收集器,您需要应用 flatMapping 电影对象 [=76] 中提取 演员 =].请注意,flatMapping expect 作为参数的函数采用流元素(电影对象)和returns一个Stream演员的名字).

然后是 flatMapping 的下游收集器,您需要再次应用 groupingBy 以创建一个嵌套地图,该地图将按 演员 对电影进行分组。由于只需要一些电影,counting() 必须用作下游收集器,以将映射到每个演员的 电影对象 减少到这些对象的数量。

然后将创建一个 Map<String, Map<String, Long>> 类型的中间映射,表示 actor 的电影总数 count.

下一步是在 条目集 上创建一个流并 展平 嵌套映射(count of movies by actor) 通过用一个新的 组合条目 包装地图中的每个条目 Map.Entry<String, Map.Entry<String, Long>> 类型,其中将包含 year演员姓名计数

最后一步是找到条目,其中最大计数

对于该操作max() 必须应用于流。它期望 Comparator 和 returns 由 Optional 包裹的结果。我假设 resume 应该存在,因此下面的代码是一个 fail-fast 实现,如果流源为空( 找不到结果,它将引发 NuSuchElementExeption ).

Comparator是使用静态方法comparingLong()定义的。它将根据 count 部电影生成比较器。

public static void main(String[] args) {
    List<Movie> movies =
            List.of(new Movie("The Avengers", "2011", List.of("Tom","Chris","Robert")),
                    new Movie("Sherlock Holmes", "2011", List.of("Robert","Harris","Murphy")),
                    new Movie("Spiderman", "2002", List.of("Tobey","William","Kirsten")));

    Map.Entry<String, Map.Entry<String, Long>> result =
        movies.stream()
            .collect(Collectors.groupingBy(Movie::getYear,
                        Collectors.flatMapping(movie -> movie.getActorList().stream(),
                             Collectors.groupingBy(Function.identity(), 
                                                   Collectors.counting()))))
            .entrySet().stream()
            .flatMap(entryYear -> entryYear.getValue().entrySet().stream()
                    .map(entryActor -> Map.entry(entryYear.getKey(),
                                            Map.entry(entryActor.getKey(), 
                                                      entryActor.getValue()))))
            .max(Comparator.comparingLong(entry -> entry.getValue().getValue()))
            .orElseThrow(); // NoSuchElementExeption will be thrown is the result wasn't found (if stream is empty)

    System.out.println(result);
}

输出

2011=Robert=2