当前位置: 首页 > 知识库问答 >
问题:

在Java中使用流从嵌套的对象列表中筛选/删除

姬承教
2023-03-14

假设我们有一个三维的物体列表。

  class OneDObject {
    int id;
    List<Integer> list;
    OneDObject(int id, List<Integer>list) { // Constructor }
    // Getters and Setters
  }

  class TwoDObject {
    int id;
    List<OneDObject> list;
    TwoDObject(int id, List<OneDObject> list) { // Constructor }
    // Getters and Setters
  }

  var l1 = List.of(1,2,4);
  var l2 = List.of(2,4,6);
  var obj1d1 = new OneDObject(1, l1);
  var obj1d2 = new OneDObject(2, l2);
  var l3 = List.of(obj1d1, obj1d2);
  var l4 = List.of(obj1d1);
  var obj2d1 = new TwoDObject(3, l3);
  var obj2d2 = new TwoDObject(4, l4);
  var l5 = List.of(obj2d1, obj2d2);   // 3-d list

假设我想过滤“l5”,这样如果最里面的列表中的任何元素是奇数,那么整个列表都应该被删除,如果这使得第二级列表为空,那么作为回报应该被删除。

因此,对于给定的示例,在过滤之前,如果:

[[[1,2,4],[2,4,6]], [[1,2,4]]]

过滤后,它应该是:

[[[2,4,6]]]

如何使用Java中的流来实现这一点?

共有3个答案

丁翰海
2023-03-14

为了实现您想要的,我们需要混合使用功能接口的流操作和收集方法

在下面的代码中,我们首先使用peek聚合操作来检查每个TwoDbObj实例。

然后,对于它们中的每一个,我们检查它们的OneDbObj列表,并删除至少包含奇数的实例。

一旦OneDbObj列表被最里面的整数列表过滤,我们只保留其列表至少包含一个值的TwoDbObj实例(它也可以被写为!isEmpty)。

public class Main {
    public static void main(String[] args) {
        List<TwoDObject> l5 = new ArrayList<>(List.of(
                new TwoDObject(3, new ArrayList<>(List.of(
                        new OneDObject(1, new ArrayList<>(List.of(1, 2, 4))),
                        new OneDObject(2, new ArrayList<>(List.of(2, 4, 6)))))),
                new TwoDObject(4, new ArrayList<>(List.of(new OneDObject(1, new ArrayList<>(List.of(1, 2, 4))))))));

        System.out.println(l5);

        List<TwoDObject> listFiltered = l5.stream()
                .peek(twoObj -> twoObj.getList().removeIf(oneObj -> oneObj.getList().stream().anyMatch(i -> i % 2 != 0))) //For each TwoDbObj we get rid of the OneDbObj list whose elements contain at least an odd number
                .filter(twoObj -> twoObj.getList().size() > 0) //Keeping only the TwoDbObj instances whose list contains any element
                .collect(Collectors.toList());

        System.out.println(listFiltered);
    }
}

在这里,我将粘贴示例类的部分实现,以便模拟我执行的测试。

class OneDObject {
    int id;
    List<Integer> list;

    OneDObject(int id, List<Integer> list) {
        this.id = id;
        this.list = list;
    }

    public List<Integer> getList() {
        return list;
    }

    public String toString() {
        return String.format("%s", list);
    }
}

class TwoDObject {
    int id;
    List<OneDObject> list;

    TwoDObject(int id, List<OneDObject> list) {
        this.id = id;
        this.list = list;
    }

    public List<OneDObject> getList() {
        return list;
    }

    public String toString() {
        return String.format("%s", list);
    }
}
尉迟招
2023-03-14

这是最后一段代码(用Java编写,但我认为它几乎可以与Kotlin互换)

List<TwoDObject> l6 = l5.stream()
                .peek(twoDObject -> {
                    List<OneDObject> filteredOneDObjectList = twoDObject.getList()
                            .stream()
                            .filter(oneDObject -> oneDObject.getList()
                                    .stream()
                                    .noneMatch(i -> i % 2 == 1))
                            .toList();

                    twoDObject.setList(filteredOneDObjectList);
                })
                .filter(twoDObject -> twoDObject.getList().size() > 0)
                .toList();

首先,我们通过调用Stream#peek遍历每个twoDObject,然后对其列表进行流式处理,过滤掉每个包含奇数的oneDObject。然后列表被保存回当前的twoDObject。

最后我们过滤掉所有空的两个对象。

请注意,Stream#peek通常只能用于调试,而不能更改流元素。
在这种情况下,它也可以用

List<TwoDObject> l6 = l5.stream()
                .map(twoDObject -> {
                    ...

                    return twoDObject;
                })
                ...
易星纬
2023-03-14

由于您需要更新列表,在下面的解决方案中,我使用ListremoveIf方法删除任何不符合必要条件的元素。因此,要想让removeIf发挥作用,列表不应该是不变的。因此,替换var list=list。关于(…) 带有var list=new ArrayList的代码

现在,这个问题可以分为以下几个部分:

  1. 谓词来标识列表中是否有任何奇数元素
Predicate<OneDObject> hasOdd = obj-> obj.getList().stream().anyMatch(i -> i % 2 != 0);
Predicate<TwoDObject> validate2d = obj -> {
    // remove any 1d list that has atleast one odd number.
    obj.getList().removeIf(hasOdd);
    // check if there are any valid 1d lists
    return obj.getList().isEmpty();
};
l5.removeIf(validate2d); // l5 will now contain only the 2d object having [2,4,6] list

 类似资料:
  • 作为这个答案的后续(关于方法1),我想更进一步: 我想根据某些标准筛选子对象。我尝试了下面的查询,但它仍然没有筛选出孙实体下的对象。 关联类实体 类关系ParentEntity<1-OneTomany-x>ChildEntity<1-OneTomany-x>GrandChildEntity

  • 我正在尝试根据另一个列表中存在的值筛选一个列表。我已经经历了其他类似的问题,并试图利用这些来实现我的目标,但无法做到这一点。 列表1由类(L1)的对象组成 列表2由类(L2)的对象组成 因此,筛选后,列表1将不包含,因为该模型与中的不匹配。 我怎么能这么做?

  • 我需要从给定的超级列表中提取子列表,如下所述。 假设我有一个“Person”对象的超级列表如下: 让Person类定义如下: 通过使用Java Streams API,我如何获取包含如下条目的子列表(注意,必须获取具有相同名称的对象的重复实例): 有人能帮我用Java 8流API实现这一点吗? 附注:我不会预先知道这些对象的名称是什么值。

  • 我正试图找出如何解决这两个问题,我有我的ES 5.6索引。 我需要创建两个单独的脚本过滤器: 1-筛选employee数组大小==3的文档 2-筛选数组第一个元素为“name”==“John”的文档 我试图做一些第一步,但我无法迭代列表。我总是有一个空指针异常错误。

  • 我使用的是spring,我用定义了bean。它是一个包含对象的列表。 这是我的数据privider类: 在configuration类中,我从创建了-它可以工作。 在服务中,我想从列表中修改一个对象,该对象与令牌字符串匹配,并且已将设置为。 这条小溪运行良好。现在,当有人为已确认的对象调用方法两次时,我希望抛出。我怎么能用这条小溪做到这一点呢?我可以将放在哪里? 编辑: 我现在的解决方案。我使用而

  • 我是Elasticsearch的新手,我试图创建一个过滤器来检索具有特定属性的文档。 属性在映射中定义为嵌套对象,如下所示: 我试图以以下形式执行一个复杂的查询: 这是elasticsearch 2.x。我做错了什么?