如何在Java中按多个属性过滤列表?

时间:2017-08-09 17:39:39

标签: java sorting lambda

我试图利用Java的功能库来过滤掉List中的一些条目。

我有一个Book对象列表,首先按书本ID排序,然后按修订号排序。下面的示例我在列表中有九个Book对象。

Book: ID 1, Revision Number 1
Book: ID 1, Revision Number 2
Book: ID 1, Revision Number 3
Book: ID 2, Revision Number 1
Book: ID 2, Revision Number 2
Book: ID 2, Revision Number 3
Book: ID 3, Revision Number 1
Book: ID 3, Revision Number 2
Book: ID 3, Revision Number 3

我想过滤列表,以便每个图书ID只有最高版本号。

Book: ID 1, Revision Number 3
Book: ID 2, Revision Number 3
Book: ID 3, Revision Number 3

Java是否具有使用过滤器或比较器之类的功能,以允许我根据公共值(书籍ID)基于多个字段进行过滤?我想尝试避免编写我自己的函数来循环收集并尽可能地进行过滤......有什么建议吗?

2 个答案:

答案 0 :(得分:4)

这样的事情:

List<Book> books = Arrays.asList(
        new Book(1, 2),
        new Book(1, 3),
        new Book(2, 2),
        new Book(2, 3)
);

System.out.println(
    books.stream()
            .collect(
                    groupingBy(Book::getID,
                        maxBy(comparingInt(Book::getRevison))
                    )
            )

);// {1=Optional[Book{ID=1, revison=3}], 2=Optional[Book{ID=2, revison=3}]}

如果最后更新,您只需List<Book>只需使用Map<Integer,Optinal<Book>>

的值的流
.values().stream().map(Optional::get).collect(Collectors.toList()));

完整的例子:

System.out.println(books.stream()
                .collect(
                        groupingBy(Book::getID,
                                maxBy(comparingInt(Book::getRevison))
                        )
                ).values()
                .stream()
                .map(Optional::get)
                .collect(Collectors.toList())
);

答案 1 :(得分:0)

这不是基于多个属性的真正过滤,但可以解决您的问题:

final Map<String, Book> books = list.stream().collect(
    Collectors.toMap(
        b -> b.getId(), 
        b -> b,
        (b1, b2) -> {
            if(b1.getNumber() > b2.getNumber()) {
                return b1;
            }
            return b2;
        })
);

它将返回包含id作为键的map,以及具有最高编号的book(具有唯一id)。

toMap收集器中,您可以添加merge function,这将决定在相同密钥发生冲突时要执行的操作。在这种情况下,它将返回更高数字的书。

如果您想要通过该电话values()收集。