查找具有名字和姓氏的演员曾使用Java 8 Streams进行工作,映射,过滤,缩小的电影

时间:2019-02-08 05:05:58

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

我正在尝试使用Java 8 Stream API,并希望使用Java 8流过滤器map reduce转换以下方法。

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

我想查找所有具有特定名字和姓氏的演员都曾参与过的电影。

下面的方法基于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;
}

如果我在电影上进行流媒体播放并将其平面映射,并在其中播放演员列表,那么在只有该名字和姓氏的演员存在的情况下,如何才能再次获得电影列表?

4 个答案:

答案 0 :(得分:3)

由于其他答案已经解决了java-8中解决问题的方式,因此,使用此解决方案,您可以使用java-9中引入的所有全新Collectors.filtering。因此,只需将其留在此处即可供将来参考。

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

答案 1 :(得分: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());

答案 2 :(得分:2)

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

this.someService.login().subscribe(res => {
  localStorage.setItem('token', res.data.token); // <-- add these lines
  localStorage.setItem('id', res.data.id);  // <-- 
});

答案 3 :(得分:1)

还有一个解决方案。

有时使用错误的收集类型会使您的生活变得困难。我建议Movie.getActors()返回一个Set<Actor>而不是一个List<Actor>。这将使处理变得容易得多。

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