【问题标题】:Filter objects by matching it with another list by its nested list elements with a condition通过使用条件的嵌套列表元素将对象与另一个列表匹配来过滤对象
【发布时间】:2019-06-20 14:19:58
【问题描述】:

我正在尝试使用 Java8 流过滤和收集具有条件的对象

我有一个实例列表,其中有一个嵌套的元素列表

public class Model {
List<Instance> instances;
}
public class Instance {
private String name;
List<Element> elements;
}
public class Element {
private String partNumber;
}

下面是josn的例子

{
    "instances": [
        {
            "name": "instance1",
            "elements": [
                {
                    "partNumber": "partNumber1"
                },
                {
                    "partNumber": "partNumber2"
                }
            ]
        },
        {
            "name": "instance2",
            "elements": [
                {
                    "partNumber": "partNumber3"
                },
                {
                    "partNumber": "partNumber4"
                }
            ]
        }
    ]
}

和其他响应对象

public class Response {
private List<Domain> domains;
}
public class Domain {
private String name;
private List<Hardware> hardwares;
}
public class Hardware {
private String partNumber;
}

示例 json

{
    "domains": [
        {
            "name": "domain1",
            "hardwares": [
                {
                    "partNumber": "partNumber1"
                }
            ]
        },
        {
            "name": "domain2",
            "hardwares": [
                {
                    "partNumber": "partNumber2"
                },
                {
                    "partNumber": "partNumber3"
                },
                {
                    "partNumber": "partNumber4"
                }
            ]
        },
        {
            "name": "domain3",
            "hardwares": [
                {
                    "partNumber": "partNumber5"
                },
                {
                    "partNumber": "partNumber6"
                }
            ]
        }
    ]
}

我正在尝试通过比较来自域的 Hardwares 是否包含来自请求的每个元素的 partnumber 来流式传输和收集响应对象。这意味着每个Instance 中至少有一个hardware 应该出现在Domains hardwares 中,以便将Domain 视为有效。

对于上述样本数据,

  1. domain1 不是有效的域,因为它只包含至少 一个partnumberpartNumber1来自instance1但不包含 至少一个partnumber 来自instance2
  2. domain2 是有效的 域,因为它至少包含一个 partnumber partNumber2 来自instance1 并包含至少一个partnumber partNumber3 来自instance2。它可以包含其他部件号,即 好的
  3. domain3 不是有效域,因为它不包含 至少一个partnumber 来自instance1 并且不包含 至少一个partnumber 来自instance2

我开始写了

request.getInstances().stream().flatMap(instance -> instance.getElement().stream().filter(element -> response.getDomains().stream().flatMap(domain -> domain.getHardwares.stream().anyMatch(hardware-> element.contains()

但由于我对流的理解有限,我很难完成这项工作

【问题讨论】:

    标签: java java-8 java-stream


    【解决方案1】:

    您可能可以在一个流中完成所有操作,但我建议使用两个流。首先,从模型中生成一组零件名称列表;然后,流式传输响应以查找域,以便对于每个实例,该域中的某个部分名称包含在该实例的部分名称集中。

    List<Set<String>> parts = model.getInstances().stream()
            .map(i -> i.getElements().stream()
                    .map(Element::getPartNumber)
                    .collect(Collectors.toSet()))
            .collect(Collectors.toList());
    
    response.getDomains().stream()
            .filter(d -> parts.stream()
                    .allMatch(p -> d.getHardwares().stream()
                            .map(Hardware::getPartNumber)
                            .anyMatch(p::contains)))
            .forEach(System.out::println);
    

    关于您的 cmets:现在,如果有一个没有元素的实例,这应该删除所有域,因为 allMatch 将针对该实例失败。如果只是忽略没有元素的实例,您可以在第一个流中添加另一个 filter 以创建 parts 列表(未测试):

            .filter(i -> ! i.getElements().isEmpty())
    

    或者i.getElements() != null,取决于它的初始化方式。

    【讨论】:

    • 感谢您的快速回复。感谢你的帮助。这适用于几乎所有实例都没有任何零件号的情况。我试图通过在此处设置条件map(i -&gt; i.getElements().stream() .map(Element::getPartNumber) .collect(Collectors.toSet())) 来限制仅在列表大小大于 0 时收集零件号,但它不起作用。我还尝试通过删除 foreach 使用 Collect(Collectors.toList()) 来收集Domains,它显示编译错误
    • 当一个实例没有任何硬件时不{ "instances": [ { "name": "instance1", "elements": [ { "partNumber": "partNumber1" }, { "partNumber": "partNumber2" } ] }, { "name": "instance2" } ] }
    • 这就是我的 Instance 类看起来像 public class Instance { private String name; List&lt;Element&gt; elements = new ArrayList&lt;&gt;(); } 的样子,因为我在这里初始化了列表,它显示它有两个 Instance2 的零件号集列表,第二个列表大小为 0
    • 它在删除初始化后工作,并在流中处理之前进行了空检查。谢谢@tobias_k
    • 也许我理解错了。你说 id 在这种情况下不起作用。那么它应该如何表现呢?那么它是否应该对所有域都失败,因为没有域具有来自该(空)实例的硬件?应该忽略那个空实例吗?请参阅我的编辑。它是这样工作的吗?
    猜你喜欢
    • 2021-12-05
    • 2017-06-14
    • 1970-01-01
    • 2021-12-01
    • 2016-03-02
    • 2018-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多