簡體   English   中英

如何通過將屬性與另一個列表中的對象進行匹配來過濾對象列表

[英]How to filter a list of objects by matching properties with objects from another list

我是 Java II 的編程學生。 我有一個對象出版物,它有兩個屬性......書籍列表和作者列表

public class Publication {
    
    public final List<Book> bookList;   
    public final List<Author> authorList;
}

public class Author {
    private final String id;
    private final String firstName;
    private final String lastName;
    private final  int age;
}
public class Book {
    private final String title;
    private final String authorId;     //this is equal to person's id who wrote the book
}   

我的任務是創建一個方法

public List<Book> getBooksByAuthorAge(int age){}

在接受 int 年齡的 Publication 類中,然后返回由該年齡的作者編寫的所有書籍。 Book 屬性“authorId”與 Author 屬性“id”相關。 所以我需要計算年齡,找到那個年齡的人,找到他們的 id,然后按那個年齡的作者列表中的 authorId 過濾書籍列表。

相比之下,我在 Java 中仍然有點弱,並試圖用流來做到這一點,但在每一步我都受阻了。 我已經開始將它分解成多個語句,首先返回具有給定年齡的人員列表,然后使用它來映射 ID 列表,然后我可以用它來與 authorIds 進行比較,但我在流中掙扎我不想回到 Java I 的舊 for 循環! 我知道在這個小方法中捆綁一堆變量太愚蠢了。 能制造出美麗溪流的人給我一點推動嗎? 非常感謝提前,真的!

以下只是部分完成並且太愚蠢了,但包括在內只是為了證明我的思想陷入困境:

//a List of authors who are of that age
        List<Author> agedResults = authorList.stream()
                .filter(p -> p.getAge() == age)
                .collect(Collectors.toList());
        
        //a list of IDs that belong to authors of that age
        List<String> agedIds = agedResults.stream()
                .map(Author::getId)
                .collect(Collectors.toList());

我建議您添加一個Author字段,而不是在Book中維護authorId 無論如何,按原樣,首先流式傳輸authorList以收集匹配的 authorId,然后流式傳輸bookList以查找匹配的書籍。 喜歡,

public List<Book> getBooksByAuthorAge(int age) {
    List<String> authorIds = authorList.stream()
            .filter(a -> a.age == age).map(a -> a.id)
            .collect(Collectors.toList());
    return bookList.stream()
            .filter(book -> authorIds.contains(book.authorId))
            .collect(Collectors.toList());
}

可以是這樣:

public List<Book> getBooksByAuthorAge(int age) {
        return bookList.stream()
                .filter(book -> authorList.stream()
                        .filter(author -> author.getAge() == age)
                        .anyMatch(author -> Objects.equals(author.getId(), book.getAuthorId())))
                .collect(Collectors.toList());
    }

但我不確定它比幾個變量更好。 代碼應該是可讀的,並且流並不總是符合這個要求。

為了方便查找作者 ID,作者應按年齡過濾並收集到Set ,允許在Set::contains進行 O(1) 查找,然后按 id 過濾書籍流:

public List<Book> getBooksByAuthorAge(int age) {
    Set<String> authorIds = authorList
                .stream()
                .filter(author -> author.getAge() == age)
                .map(Author::getId)
                .collect(Collectors.toSet());

    return bookList
            .stream()
            .filter(book -> authorIds.contains(book.getAuthorId()))
            .collect(Collectors.toList());
}

但是,在“現實世界”中,一本書可能由多個人創作,因此如果Book類更改為支持List<String> authorIds而不是單個String authorId ,則可以應用以下操作:

public List<Book> getBooksWithSeveralAuthorsByAuthorAge(int age) {
    Set<String> authorIds = authorList
                .stream()
                .filter(author -> author.getAge() == age)
                .map(Author::getId)
                .collect(Collectors.toSet());

    return bookList
            .stream()
            .filter(book -> book
                .getAuthorIds()  // assuming List<String> is returned here
                .stream() // Stream<String>
                .anyMatch(authorIds::contains)
            )
            .collect(Collectors.toList());
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM