使用 Java 流过滤嵌套列表
Filtering of nested lists with Java Streams
我需要过滤一些嵌套列表。考虑一个包含 List<B>
的 List<A>
,其中包含 List<C>
。我需要过滤,return 所有包含至少一个满足给定条件的 B 和至少一个满足给定条件的 C 的 A 对象。
我在下面有一个人为的例子,它基本上是在做我在我的实际例子中试图实现的事情。拿一个城市的学校列表,每个学校有很多学科,每个学科有很多老师。我想保留一份包含 subject.subjectName = 'Math' 的学校列表,并且该科目中至少有一名教师 teacher.age > 65.
我已经使用自定义谓词实现了这个,所以我也在我的示例中做了一个 this。
我在 'cannot convert from boolean to 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;
}
如果您尝试 return 父对象,则不要使用 flatMap()
。您只需要嵌套一些 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());
由于您正在寻找 School
s 作为输出,因此您不需要将您的流 map
/flatmap
转换为另一个对象。 filter
ing 功能必须足够智能,能够遍历嵌套集合并根据您的要求确认是否存在 anyMatch
。
主要在下面的代码中,我们过滤了所有开设名为“数学”的科目并且其中一位教授数学的老师超过上述退休年龄的学校。
// 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());
我需要过滤一些嵌套列表。考虑一个包含 List<B>
的 List<A>
,其中包含 List<C>
。我需要过滤,return 所有包含至少一个满足给定条件的 B 和至少一个满足给定条件的 C 的 A 对象。
我在下面有一个人为的例子,它基本上是在做我在我的实际例子中试图实现的事情。拿一个城市的学校列表,每个学校有很多学科,每个学科有很多老师。我想保留一份包含 subject.subjectName = 'Math' 的学校列表,并且该科目中至少有一名教师 teacher.age > 65.
我已经使用自定义谓词实现了这个,所以我也在我的示例中做了一个 this。 我在 'cannot convert from boolean to 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;
}
如果您尝试 return 父对象,则不要使用 flatMap()
。您只需要嵌套一些 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());
由于您正在寻找 School
s 作为输出,因此您不需要将您的流 map
/flatmap
转换为另一个对象。 filter
ing 功能必须足够智能,能够遍历嵌套集合并根据您的要求确认是否存在 anyMatch
。
主要在下面的代码中,我们过滤了所有开设名为“数学”的科目并且其中一位教授数学的老师超过上述退休年龄的学校。
// 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());