简体   繁体   English

使用Java 8 Stream API过滤嵌套列表

[英]Filter on nested list using Java 8 Stream API

I'm not able to convert below snippet in Java 8 stream format. 我无法以Java 8流格式转换下面的代码段。

List<String> titles = Arrays.asList("First Name", "Last Name");

for (FirstClass first : firstClassList) {
    for (SecondClass second : first.getSecondClassList()) {
        for (ThirdClass third : second.getThirdClassList()) {                   

            if(!titles.contains(third.getField())) {
                second.getThirdClassList().remove(third);
            }

        }
    }
}  

I'm comparing third level nested list object against the input list of fields. 我正在将第三级嵌套列表对象与输入字段列表进行比较。 If fields are not matching then I'm removing them from original list. 如果字段不匹配,那么我将它们从原始列表中删除。 How can I achieve this using Java 8 syntax. 如何使用Java 8语法实现此目的。

Edit: I want List of FirstClass to be returned. 编辑:我想要返回FirstClass列表。

I don't think streams win you anything in this case. 在这种情况下,我认为溪流不会赢得任何东西。 All you do is iterate over the nested lists and either the enhanced for loop or forEach is more straightforward. 您所做的就是迭代嵌套列表,增强的for循环或forEach更直接。

The improvements can come from using removeIf to modify the list and, possibly, from moving the rejection logic out of the loop: 这些改进可以来自使用removeIf来修改列表,也可能来自将拒绝逻辑移出循环:

Predicate<ThirdClass> reject = third -> !titles.contains(third.getField());

firstClassList.forEeach(first ->
    first.getSecondClassList().forEach(second ->
        second.getThirdClassList().removeIf(reject)
    )
);

Get a stream of SecondClass objects by flattening the firstClassList and for each SecondClass get the filtered list of ThirdClass objects and set it back in the SecondClass 通过展平firstClassList获取SecondClass对象流,并为每个SecondClass获取已过滤的ThirdClass对象列表并将其设置回SecondClass

List<String> titles = Arrays.asList("First Name", "Last Name");

firstClassList
    .stream()
    .flatMap(firstClass -> firstClass.getSecondClassList().stream())
    .forEach(secondClass -> {
             List<ThirdClass> filteredThirdClasses = secondClass.getThirdClassList()
                        .stream()
                        .filter(thirdClass -> titles.contains(thirdClass.getField()))
                        .collect(toList());

             secondClass.setThirdClassList(filteredThirdClasses);
         }
    );

First you can use Stream.map() and Stream.flatMap() to get a Stream containing a List of ThirdClass . 首先,你可以使用Stream.map()Stream.flatMap()获得Stream包含ListThirdClass To remove the items matching the condition you could use Collection.removeIf() , which removes all items from a collection matching the given condition: 要删除与条件匹配的项,可以使用Collection.removeIf() ,它会删除与给定条件匹配的集合中的所有项:

firstClassList.stream()                         // Stream<FirstClass>
        .map(FirstClass::getSecondClassList)    // Stream<List<SecondClass>>
        .flatMap(Collection::stream)            // Stream<SecondClass>
        .map(SecondClass::getThirdClassList)    // Stream<List<ThirdClass>>
        .forEach(thirdList -> thirdList.removeIf(third -> !titles.contains(third.getField())));

This modifies the original List, just like you did in your example. 这会修改原始List,就像您在示例中所做的那样。 You then can use firstClassList as result for further processing. 然后,您可以使用firstClassList作为结果进行进一步处理。

Beside that I would recommend using a Set<String> instead of a List<String> for your titles, because it has a time complexity of O(1) instead of O(n) : 除此之外,我建议使用Set<String>而不是List<String>作为标题,因为它的时间复杂度为O(1)而不是O(n)

Set<String> titles = new HashSet<>(Arrays.asList("First Name", "Last Name"));

Assuming the three levels in your data-structure are collections then a solution could be: 假设数据结构中的三个级别是集合,那么解决方案可以是:

  1. flatten the structure to a stream of the leaf level 将结构展平为叶片水平
  2. filter by the required titles 按所需标题过滤
final List<ThirdClassList> results = firstClassList
    .stream()
    .flatMap(FirstClassList::getSecondClassList)
    .flatMap(FirstClassList::getThirdClassList)
    .filter(third -> !titles.contains(third))
    .collect(toList());

This will give you the leaf level objects to be removed, though this is only half the solution of course, you still want to remove them. 这将为您提供要删除的叶级对象,尽管这只是解决方案的一半,您仍然希望删除它们。

If you are the author of the list classes then perhaps you could have a reference from each third level to its 'parent' second level so removing is then a relatively simple second step: 如果您是列表类的作者,那么也许您可以从每个第三级到其“父级”第二级引用,因此删除是一个相对简单的第二步:

results.forEach(third -> third.parent().remove(this));

where third.parent() returns the second level object. 其中third.parent()返回第二级对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM