【问题标题】:Find Movies where an actor with first and last name has worked using Java 8 Streams, map, filter, reduce查找具有名字和姓氏的演员使用 Java 8 Streams、map、filter、reduce 工作过的电影
【发布时间】:2023-03-31 02:50:01
【问题描述】:

我正在尝试使用 Java 8 Stream API 并想使用 Java 8 流过滤器映射减少转换以下方法。

我有一个电影列表,每个电影对象都有一个演员列表以及其他字段。

我想查找具有特定名字和姓氏的演员在其中工作的所有电影。

下面的方法是基于 Java 7 的,我循环遍历电影列表,然后遍历该电影的演员列表。如果找到具有该名字和姓氏的演员,我会中断内部循环并将该电影添加到返回的电影列表中。

注释代码有效,我可以获得正确的电影列表。

我的问题是如何使用 Java 8 流重写此代码。我可以看到这是一个映射、过滤、减少问题,但我无法提出明确的解决方案。

public List<Movie> getMoviesForActor(String firstName, String lastName) {

    final List<Movie> allMovies = movieRepository.getAllMovies();
    final Predicate<Actor> firstNamePredicate = actor -> actor.getFirstName().equalsIgnoreCase(firstName);
    final Predicate<Actor> lastNamePredicate = actor -> actor.getLastName().equalsIgnoreCase(lastName);

    final List<Movie> movies = new ArrayList<>();
    //        for (Movie movie : allMovies) {
    //            boolean actorFound = false;
    //            for (Actor actor : movie.getActors()) {
    //                if(firstName.equalsIgnoreCase(actor.getFirstName()) && lastName.equalsIgnoreCase(actor.getLastName())) {
    //                    actorFound = true;
    //                    break;
    //                }
    //            }
    //            if(actorFound) {
    //                movies.add(movie);
    //            }
    //        }

    final List<Actor> actors = allMovies.stream()
            .flatMap(
                    movie -> movie.getActors().stream().filter(firstNamePredicate.and(lastNamePredicate))
            ).collect(Collectors.toList());
    return movies;
}

如果我在电影上进行流式传输并对其进行平面映射并在其中流式传输演员列表,我如何才能再次获取仅存在具有名字和姓氏的演员的电影列表?

【问题讨论】:

    标签: java dictionary java-8 java-stream reduce


    【解决方案1】:

    由于其他答案已经解决了您在java-8 中解决问题的方法,通过此解决方案,您可以使用java-9 中引入的全新Collectors.filtering。因此,请将其留在这里以供将来参考。

    List<Movie> movies = allMovies.stream()
                    .collect(Collectors.filtering(
                          m -> m.getActors().stream().anyMatch(firstNamePredicate.and(lastNamePredicate)),
                    Collectors.toList()));
    

    【讨论】:

    • 有趣的选择。请记住,filtering() 收集器在用于多级归约时最有用,例如groupingBypartitioningBy 的下游
    【解决方案2】:

    使用 Java8 中的 anyMatch 短路终端操作可以轻松实现在循环遍历可迭代对象时找到第一个匹配元素并在找到后中断。然后将anyMatch 的结果传递给filter 运算符以获取所有符合给定条件的电影。

    我宁愿建议您使用内联谓词而不是单独定义它们,除非您在其他地方重用它们。这导致更简洁的代码,更少冗长。这是它的外观。

    movies.stream()
        .filter(m -> m.getActors().stream()
            .anyMatch(
                a -> a.getFirstName().equalsIgnoreCase(firstName) 
                    && a.getLastName().equalsIgnoreCase(lastName)))
        .collect(Collectors.toList());
    

    出于某种原因,如果您确实需要使用问题陈述中给出的预定义谓词,您可以这样做,

    movies.stream()
        .filter(m -> m.getActors().stream()
            .anyMatch(firstNamePredicate.and(lastNamePredicate)))
        .collect(Collectors.toList());
    

    【讨论】:

      【解决方案3】:

      使用现有代码编写它的更好方法(功能)是:

      final Predicate<Movie> movieIncludesActor = movie -> movie.getActors()
              .stream()
              .anyMatch(firstNamePredicate.and(lastNamePredicate)); // check both the condition for all actors
      final List<Movie> movies = allMovies.stream()
              .filter(movieIncludesActor) // movie which has such an actor
              .collect(toList());
      

      【讨论】:

        【解决方案4】:

        还有一个解决方案。

        有时使用错误的集合类型会让您的生活变得困难。我建议Movie.getActors() 返回Set&lt;Actor&gt; 而不是List&lt;Actor&gt;。这将使处理更容易。

        private class Movie {
            public Set<Actor> getActors() {
                return null;
            }
        }
        
        private class Actor {
            private final String firstName;
            private final String lastName;
        
            private Actor(String firstName, String lastName) {
                this.firstName = firstName;
                this.lastName = lastName;
            }
        
            public String getFirstName() {
                return firstName;
            }
        
            public String getLastName() {
                return lastName;
            }
        
            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (!(o instanceof Actor)) return false;
                Actor actor = (Actor) o;
                return firstName.equals(actor.firstName) &&
                        lastName.equals(actor.lastName);
            }
        
            @Override
            public int hashCode() {
                return Objects.hash(firstName, lastName);
            }
        }
        
        final List<Movie> allMovies = Collections.EMPTY_LIST;
        
        public List<Movie> getMoviesForActor(String firstName, String lastName) {
            Actor actor = new Actor(firstName, lastName);
        
            return allMovies.stream()
                    .filter(m -> m.getActors().contains(actor))
                    .collect(Collectors.toList());
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-22
          • 1970-01-01
          • 2015-06-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多