Java流过滤

4

你好,我有一个DTO列表,并且其中的标志是已删除。我需要筛选它们并返回一个。

逻辑是如果列表中有两个项目,其中一个被删除了,那么我会获取未被删除的一个,但如果只有一个项目被删除,则返回它。

所以基本上顺序是:未删除的项目 > 已删除的项目 > 新项目。

List<Item> existingItems = service.getItems();
existingItems.stream().filter(e -> !e.getIsDeleted()).findAny().orElse(new Item());

我该如何修改这个Stream管道来实现所需的逻辑呢?

那么这个列表的最大大小始终为2吗? - JDC
不,它可以是0个或多个。 - DanJo
但是最大尺寸为2?所以是0、1还是2? - JDC
3个回答

7
您可以在orElse中返回List的第一个元素:
existingItems.stream()
             .filter(e -> !e.getIsDeleted())
             .findAny()
             .orElse(existingItems.isEmpty() ? new Item() : existingItems.get(0));

如果列表为空,它将不会返回任何内容,如果列表为空,我需要返回新的Item()。 - DanJo
1
你或许应该使用existingItems而不是list,这样更清晰明了。 - JDC

5
你可以通过按照 getIsDeleted 进行排序来实现这一点:
existingItems.stream()
             .sorted( Comparator.comparing(Item::getIsDeleted ) )
             .findFirst()
             .orElseGet(Item::new);

这个解决方案假设existingItems只包含少量项目。

有没有可能在.sorted()中传递两个条件,例如:Comparator.comparing(Item::getIsDeleted)和Comparator.comparing(Item::getValidFrom)? - DanJo
3
不错的答案。一个小改进是可以懒加载创建 Item:使用 .orElseGet(Item::new) - shmosel
2
它看起来确实很优雅,但是它需要O(nlogn)的时间,而没有排序的解决方案在最坏情况下只需要线性时间。 - Eran
我假设 n 很小,否则我可能会将这个谓词推到数据库中,或以不同的方式存储此列表。 - WW.
3
@DanJo Comparator.comparing(Item::getIsDeleted).thenComparing(Item::getValidFrom) - Holger
1
你也可以使用.stream().min(Comparator.comparing(Item::getIsDeleted)) - shmosel

4
我加入得比较晚。回答你的评论@Danjo。 使用上面的代码。
existingItems.stream().sorted(Comparator.comparing(Item::getIsDeleted)
  .thenComparing(Comparator.comparing(Item::getValidFrom)))
             .findFirst()
             .orElse(new Item());

你确定它编译通过了吗?类型推断在链接比较器时容易出错。 - shmosel
1
不,我没有机会编译代码。我认为它应该可以工作,因为使用了方法引用。此外,比较器可以明确创建并稍后添加。请验证我的理解。 - Ashish Lohia
2
只要在“Item”中只有一个名为“getIsDeleted”的方法,它就可以正常工作,因此无需在多个方法之间选择“Item :: getIsDeleted”。 - Holger
没错。我刚刚回答了@DanJo添加的评论。 例如:Comparator.comparing(Item::getIsDeleted )和Comparator.comparing(Item::getValidFrom),是否有可能传递两个条件给.sorted()方法? - Ashish Lohia

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