简体   繁体   English

使用 Java Streams 过滤嵌套列表

[英]Filtering of nested lists with Java Streams

I have a to filter on some nested Lists.我需要过滤一些嵌套列表。 Consider a List<A> which contains List<B> which contains List<C> .考虑一个包含List<B>List<A> ,其中包含List<C> I need to filter, to return all the A Objects which contain at least one B which satisfies a given condition, and at least one C which satisfies a given condition.我需要过滤,返回包含至少一个满足给定条件的 B 和至少一个满足给定条件的 C 的所有 A 对象。

I've got a contrived example below, which basically is doing what I've tried to implement in my actual example.我在下面有一个人为的例子,它基本上是在做我在我的实际例子中试图实现的事情。 Take a list of schools in a city Each school has many subjects, and each subject has many teachers.拿一个城市的学校列表,每个学校有很多学科,每个学科有很多老师。 I want to retain a list of schools which has subject.subjectName = 'Math' and at least one teacher within this subject where teacher.age > 65.我想保留一份包含 subject.subjectName = 'Math' 的学校列表,并且该科目中至少有一名教师 teacher.age > 65。

I have implemented this using a custom predicate, so I've also made a this in my example.我已经使用自定义谓词实现了这个,所以我也在我的示例中做了一个 this 。 I'm getting an error where 'cannot convert from boolean to Stream' but honestly, I'm struggling in this scenario.我收到“无法从 boolean 转换为 Stream”的错误,但老实说,我在这种情况下很挣扎。

    @Getter
    @Setter
    class School {
        private String schoolId;
        private List<Subject> classes;
        
    }
        
    @Getter
    @Setter
    class Subject {
        String subjectName;
        List<Teacher> teachers;
    }
    
    @Getter
    @Setter
    class Teacher {
        private String teacherName;
        private Integer age;
    }

    public class TestClass {
        public static void main( String[] args ){
            List<School> schools;
            
            // Get All schools where A mathTeacher is over retirement age
            List<School> schoolsWithRetirementAgeMathTeachers = schools.stream()
                    .filter(school -> null != school.getClasses())
                    .flatMap(school -> {
                        return school.getClasses().stream()
                                .filter(subject -> subject.getSubjectName().equalsIgnoreCase("Math"))
                                .filter(subject -> null != subject.getTeachers())
                                .flatMap(subject -> {
                                    return subject.getTeachers().stream()
                                            .filter(teacher -> teacher != null)
                                            .anyMatch(isRetirementAge);
                                });
                    }).collect(Collectors.toList());
                    
        }
                
        public static Predicate<Teacher> isRetirementAge = teacher -> teacher.getAge() > 65;
    
    }

If you're trying to return the parent objects, you don't want to use flatMap() .如果你试图返回父对象,你不想使用flatMap() You just need to nest some anyMatch() calls:您只需要嵌套一些anyMatch()调用:

List<A> filtered = listA.stream()
        .filter(a -> a.getListB()
                .stream()
                .anyMatch(b -> testB(b) && b.getListC()
                        .stream()
                        .anyMatch(c -> testC(c))))
        .collect(Collectors.toList());

Since you are looking for School s as an output, you do not need to map / flatmap your stream into another object. The filter ing capability has to be smart enough to go through the nested collections and confirm if there was anyMatch based on your requirements.由于您正在寻找School作为 output,因此您不需要将map / flatmap您的 stream 平面映射到另一个 object。 filter功能必须足够智能,通过嵌套的anyMatch根据您的要求确认 88354248716628 .

Primarily in the below code, we filter all those schools where a subject by the name "Math" is present and one of the teachers teaching Maths is above the mentioned retirement age.主要在下面的代码中,我们过滤了所有存在名称为“数学”的科目并且其中一位教授数学的老师超过上述退休年龄的学校。

// Get All schools where a Math teacher is over retirement age
List<School> schoolsWithRetirementAgeMathTeachers = schools.stream()
        .filter(school -> school.getSubjects()
                .stream()
                .anyMatch(subject ->
                        subject.getName().equalsIgnoreCase("Math") &&
                                subject.getTeachers()
                                        .stream()
                                        .anyMatch(isRetirementAge)
                ))
        .collect(Collectors.toList());

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

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