使用 Java 8 Streams 从列表中仅获取所需的对象

Posted

技术标签:

【中文标题】使用 Java 8 Streams 从列表中仅获取所需的对象【英文标题】:Getting only required objects from a list using Java 8 Streams 【发布时间】:2015-11-14 22:19:42 【问题描述】:

考虑一个具有attrib1attrib2List<Child> 属性的Parent 子类及其对应的getter 和setter。

Child 是另一个类,具有五个属性 attrib1-attrib5 及其对应的 getter 和 setter。

现在我创建了一个List<Parent> 父级。然后我想过滤掉一个List<Parent>,条件如下:-Child.Attrib1 > 10;

所以我通过 Java 8 流创建了以下查询。

parent.stream().filter(e -> e.getChild().stream().anyMatch(c -> c.getAttrib1() > 10));

但问题是我会得到每个Parent 对象中的所有孩子。在这里,我只想获取List<Child> 中符合给定条件的那些子对象。

我应该如何删除 List 中不符合条件的所有子对象并获取新的 List。

【问题讨论】:

【参考方案1】:

如果您想接收所有孩子,您需要的是Stream<Child>。以下表达式可能会起作用:

parents.stream().flatMap(e -> e.getChildren().stream()).filter(c -> c.getAttrib1() > 10)

这应该返回列表中get属性值大于10的所有父母的所有孩子。

如果您想通过删除所有不符合条件的子元素来更新父列表,您可以执行以下操作:

parents.forEach(p -> p.getChildren().removeIf(c -> c.getAttrib1() > 10));

这不会创建新列表。相反,它会更新 parents 列表本身。

【讨论】:

通过 flatmap ,我将如何获得 List 的过滤列表 据我了解,您的要求是在 getAttrib1() > 10 的父母列表中找到所有孩子。 List<Parent> 出现在哪里? flatMap 正在将父对象中的所有子流合并为一个子流。 我的要求是删除List中所有不符合条件的子对象,并得到新的List 一个完全不同的问题:(。更新答案。 parents.removeIf 从列表中删除 Parent 对象(不是从 Child 列表中匹配的子对象)。这就是你想要的吗?【参考方案2】:

据我所知,您应该为子列表添加额外的过滤器:

 parent.stream().filter(e -> e.getChild().stream().anyMatch(c -> c.getAttrib1() > 10)).forEach(e -> e.setChild(e.getChild().stream().filter(c -> c.getAttrib1 > 10).collect(toList())))

如果你还没有setChild:

您可以从列表中删除项目 创建全新的父对象

要删除你可以使用迭代器:

parent.stream().filter(e -> e.getChild().stream().anyMatch(c -> c.getAttrib1 > 10))
   .forEach(e -> 
      for(Iterator<Child> it = e.getChild().iterator(); it.hasNext();)
          Child cur = it.next();
          if(cur.getAttrib1() <= 10) it.remove();
    
)

【讨论】:

@sibnick:如果没有setChild,有什么办法可以实现。【参考方案3】:

我知道这个问题已经有将近 2 年的历史了,但希望这个答案可以对某人有所帮助。

有一个名为 com.coopstools.cachemonads 的库。它扩展了 java 流(和可选)类以允许缓存实体以供以后使用。

可以通过以下方式找到解决方案:

List<Parent> goodParents = CacheStream.of(parents)
            .cache()
            .map(Parent::getChildren)
            .flatMap(Collection::stream)
            .map(Child::getAttrib1)
            .filter(att -> att > 10)
            .load()
            .distinct()
            .collect(Collectors.toList());

其中,parents 是一个数组或流。

为了清楚起见,缓存方法是存储父母的;加载方法是将父母拉回来的原因。如果父级没有子级,则在第一个映射之后需要一个过滤器来删除空列表。

此库可用于需要对子项执行操作的任何情况,包括 map/sort/filter/etc,但仍需要较旧的实体。

代码可以在https://github.com/coopstools/cachemonads 找到(我在自述文件中包含了你的示例),或者可以从 maven 下载:

<dependency>
    <groupId>com.coopstools</groupId>
    <artifactId>cachemonads</artifactId>
    <version>0.2.0</version>
</dependency>

(或者,gradle,com.coopstools:cachemonads:0.2.0)

【讨论】:

以上是关于使用 Java 8 Streams 从列表中仅获取所需的对象的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Java 8 Streams 中获取 Inputstream?

使用 Java-8 Streams API 将字符串列表转换为 Map

如何使用 jquery 从 asp.net 列表框中仅获取当前选定的选项

弹簧数据 JPA。如何从 findAll() 方法中仅获取 ID 列表

Java 8 Streams 减少删除重复项,保留最新条目

如何使用 Java Streams 从 HashMap 的 ArrayList 中获取字符串