【问题标题】:Getting only required objects from a list using Java 8 Streams使用 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。

【问题讨论】:

    标签: java arraylist java-8 java-stream


    【解决方案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)

    【讨论】: