提问人:CurvedHalo 提问时间:3/30/2022 更新时间:3/30/2022 访问量:2271
使用 Java Streams 过滤嵌套列表
Filtering of nested lists with Java Streams
问:
我有一个可以过滤一些嵌套列表。考虑一个包含 哪个包含 的 。我需要过滤,以返回所有包含至少一个满足给定条件的 B 和至少一个满足给定条件的 C 的 A 对象。List<A>
List<B>
List<C>
我在下面有一个人为的例子,它基本上是在做我在实际示例中尝试实现的事情。以一个城市的学校列表为例,每所学校都有很多科目,每个科目都有很多老师。我想保留 subject.subjectName = 'Math' 的学校列表,并且该科目中至少有一名教师的 teacher.age > 65。
我已经使用自定义谓词实现了这一点,因此我也在我的示例中创建了一个 this。 我收到一个错误,即“无法从布尔值转换为流”,但老实说,我在这种情况下很挣扎。
@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;
}
答:
3赞
shmosel
3/30/2022
#1
如果尝试返回父对象,则不想使用 .您只需要嵌套一些调用: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());
评论
0赞
CurvedHalo
3/31/2022
如果我想扩展它,而不是只检查嵌套值的存在,我想过滤掉所有不满足条件的值?也就是说,每个项目都只有一个满足条件的项目。同样,每个都有一个,它只包含那些满足 .. 条件的项目。我该怎么做?它实质上是将嵌套筛选和将筛选器保留在流范围之外A
List<B>
testB()
B
List<C>
C
testC()
0赞
shmosel
4/1/2022
然后,您需要创建一个每个元素的过滤副本。除非您愿意就地修改列表。map()
0赞
experiment unit 1998X
10/12/2023
如果我希望获得每个元素的过滤副本,但我也不想修改原始副本,这是否意味着我必须创建具有过滤 b 副本和 c 过滤副本的 A 副本?
1赞
shmosel
10/13/2023
@experimentunit1998X 这只会过滤掉顶级元素(基于嵌套内容)。如果要在多个级别创建过滤副本,可以添加一个方法来 like .A
A filtered(Predicate<B> p1, Predicate<C> p2) { return new A(bList.stream().filter(p1).map(b -> b.filtered(p2)).toList()); }
0赞
Naman
3/30/2022
#2
由于您正在寻找 s 作为输出,因此您不需要/将流/到另一个对象中。ing 功能必须足够智能,才能遍历嵌套集合并确认是否存在基于您的要求的集合。School
map
flatmap
filter
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());
评论
0赞
CurvedHalo
3/31/2022
如果我想扩展它,只保留“主题”列表中名称 = math 的实例,即我想过滤掉这些实例。因为目前它只是用一场比赛返回学校,但下面的所有科目仍然存在
0赞
Naman
4/1/2022
要获得学校的科目,那么您必须流map
评论
C
B