Java 8中的流过滤器:对象列表列表

3
我想按照对象字段进行筛选。
List<Book> = Arrays.asList<book1, book2, book3>;

class Book {
    String author;
    List<Language>;
}

class Language {
    String locale;
    int code;
}

Book book1 = new Book("author1", Arrays.asList(new Language("en", 1), new Language("fr", 3)));
Book book2 = new Book("author2", Arrays.asList(new Language("ca", 2), new Language("fr", 3)));
Book book3 = new Book("author3", Arrays.asList(new Language("en", 1)));

我希望能得到一份不包含英语的书籍清单。
结果应该是:
List<Book> = Arrays.asList<book1, book2>;

Book book1 = new Book("author1", Arrays.asList(new Language("fr", 3)));
Book book2 = new Book("author2", Arrays.asList(new Language("ca", 2), new Language("fr", 3)));

我试图这样做:但它没有从book1中删除'en'。
return books
        .stream()
        .filter(book -> book.getLanguages()
                .stream()
                .allMatch(value -> !"en".equals(value.getLanguage())))
        .collect(Collectors.toList());
2个回答

2

首先,您可以使用filter检查任何Language对象是否具有值en,然后使用findFirst获取匹配的Language对象

return books.stream()
            .filter(book -> !book.getLanguages()
                  .stream()
                  .filter(value -> "en".equals(value.getLanguage()))
                  .findFirst().isPresent())
    .collect(Collectors.toList());

这种方式比OP在问题中发布的代码更好在哪里?你只是以一种不太易读的方式重写了OP的代码,而没有回答实际的问题。 - ETO

0

你的问题有点令人困惑,但从你的例子中我理解到有两个要求:

  1. 从每本书中过滤掉“en”语言
  2. 过滤掉只有“en”语言的书籍

你可以定义一个像这样的辅助方法:
private Book removeLanguage(Book book, String locale) {
    List<Language> languages = book.getLanguages()
                                   .stream() 
                                   .filter(l -> !l.getLocale().equals(locale))
                                   .collect(Collectors.toList());
    
    // if all languages have been removed
    if(languages.isEmpty()) return null;
    // if no languages have been removed
    if(languages.size() == book.getLanguages().size()) return book;
    // return new book with filtered list of languages
    return new Book(book.getAuthor(), languages);
}

然后按照以下方式使用:

public List<Book> removeLanguage(List<Book> books, String locale) {
    return books.stream()
                .map(b -> removeLanguage(b, locale))
                .map(Objects::notNull)
                .collect(Collectors.toList());
}

// ...

List<Book> nonEnglishBooks = removeLanguage(books, "en");

您确实可以将所有内容合并为单个链式管道。它会有一些对象创建的开销,但在小量数据上仍然表现良好:

String localeToRemove = "en";

List<Book> nonEnglishBooks = 
    books.stream()
         .map(b -> new Book(b.getAuthor(), 
                            b.getLanguages()
                             .stream() 
                             .filter(l -> !l.getLocale().equals(localeToRemove))
                             .collect(Collectors.toList())
         .filter(b -> !b.getLanguages().isEmpty())
         .collect(Collectors.toList());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接