【问题标题】:How to filter a list of objects by matching properties with objects from another list如何通过将属性与另一个列表中的对象匹配来过滤对象列表
【发布时间】:2021-12-05 01:45:57
【问题描述】:

我是一名 Java II 编程专业的学生。我有一个具有两个属性的对象 Publication... 书籍列表和作者列表

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

【问题讨论】:

    标签: java list collections java-stream


    【解决方案1】:

    为了方便查找作者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&lt;String&gt; 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());
    }
    

    【讨论】:

      【解决方案2】:

      可以这样:

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

      但我不确定它是否比几个变量更好。代码应该是可读的,并且流并不总是符合此要求。

      【讨论】:

        【解决方案3】:

        建议您添加一个Author 字段,而不是在Book 中维护authorId。无论如何,首先流式传输authorList 以收集匹配的作者ID,然后流式传输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());
        }
        

        【讨论】:

        • 您应该在authorList.stream.. 中返回set (Collectors.toSet())。在一个集合上,查找可以在 O(1) 中完成;在列表中,它是 O(n)。
        猜你喜欢
        • 1970-01-01
        • 2017-06-14
        • 2021-08-10
        • 1970-01-01
        • 2021-12-01
        • 2019-05-25
        • 1970-01-01
        • 2016-03-02
        • 1970-01-01
        相关资源
        最近更新 更多