使用Java 8过滤具有多个条件的流,直到结果不为空
我有一个名为使用Java 8过滤具有多个条件的流,直到结果不为空,java,arraylist,filter,java-8,enums,Java,Arraylist,Filter,Java 8,Enums,我有一个名为Student的对象的ArrayList。 我想筛选此列表,并仅基于层次条件返回单个学生对象 条件如下: 选择第一个COMP学员 如果未返回任何值,请选择一名经济系学生 如果没有返回,请选择一名农业专业学生 。。。等等 在我的设计中,我已经硬编码了这个-但也许它可以使用排序的集合或列表或其他东西 我当前的代码可以工作,但看起来很凌乱,如果引入更多的条件,代码会变得相当大 我需要有关学生过滤器Student(List studentList)方法的帮助。如何在更少的代码行或方法链接
Student
的对象的ArrayList
。
我想筛选此列表,并仅基于层次条件返回单个学生对象
条件如下:
- 选择第一个COMP学员
- 如果未返回任何值,请选择一名经济系学生
- 如果没有返回,请选择一名农业专业学生
- 。。。等等
集合
或列表
或其他东西
我当前的代码可以工作,但看起来很凌乱,如果引入更多的条件,代码会变得相当大
我需要有关学生过滤器Student(List studentList)
方法的帮助。如何在更少的代码行或方法链接中做到这一点。以及如何引入一个排序的集合
,枚举
,该集合可以根据偏好进行筛选(例如,COMP first,if empty,然后ECON next,等等。如果找到一个,则停止筛选)
代码:
import java.util.ArrayList;
导入java.util.array;
导入java.util.List;
导入java.util.Optional;
班级学生{
私人最终int stNumber;
私有最终字符串stModule;//…更多字段
公立学生(整数stNumber,字符串stModule){
this.stNumber=stNumber;
this.stModule=stModule;
}
public int getStNumber(){
返回stNumber;
}
公共字符串getStModule(){
返回模块;
}
@凌驾
公共字符串toString(){
返回“学生{”+
“stNumber=“+stNumber+
“,stModule='”+stModule+'\''+
'}';
}
}
枚举模块{
公司(“计算机”),
经济学(“经济学”),
农业(“农业”),
物理(“物理学”);/…非常大的列表
私有字符串moduleName;
公共字符串getModuleName(){
返回模块名;
}
模块(字符串moduleName){
this.moduleName=moduleName;
}
}
公开课问题{
公共静态void main(字符串[]args)引发异常{
//这些列表可以是任意大小并包含任何信息
List studentListOne=Arrays.asList(
新生(41,“经济学”),
新生(45,“计算机”)
);
List studentlistwo=Arrays.asList(
新生(11,“物理”),
新生(23,“农业”),
新生(86,“物理”),
新生(34,“经济学”)
);
List studentListThree=新建ArrayList();
System.out.println(filterStudent(studentListOne));
System.out.println(filterStudent(studentlistwo));
System.out.println(filterStudent(studentListThree));//异常
}
/**
*规则是:选择COMP学生的第一个实例。
*如果列表为空,请选择一名经济系学生。
*如果列表仍然为空,请选择一名农业学生。
*
*@param studentList
*@留学生
*/
公共静态学生筛选器学生(列表学生列表)引发异常{
选修学生;
selectedStudent=studentList.stream().filter(student->student.getStModule().equalsIgnoreCase(Module.COMP.getModuleName()).findFirst();
如果(selectedStudent.isPresent()){
返回selectedStudent.get();
}
selectedStudent=studentList.stream().filter(student->student.getStModule().equalsIgnoreCase(Module.ECON.getModuleName()).findFirst();
如果(selectedStudent.isPresent()){
返回selectedStudent.get();
}
selectedStudent=studentList.stream().filter(student->student.getStModule().equalsIgnoreCase(Module.AGRI.getModuleName()).findFirst();
如果(selectedStudent.isPresent()){
返回selectedStudent.get();
}
抛出新异常(“未找到符合条件的学生”);
}
}
您可以使用循环重写当前方法:
for (Module mod : Arrays.asList(Module.COMP, Module.ECON, Module.AGRI)) {
String subj = mod.getModuleName();
Optional<Student> selectedStudent = studentList.stream().filter(student -> student.getStModule().equalsIgnoreCase(subj)).findFirst();
if (selectedStudent.isPresent()) {
return selectedStudent.get();
}
}
throw new Exception(...);
这可能很好。如果您想使用更明确的列表,您可以在找到COMP
学生后立即停止:
Student best = null;
for (Student student : studentList) {
int comp = comparator.compare(best, student);
if (comp > 0) {
best = student;
int studentOrder = studentOrdering.apply(student);
if (studentOrder == 0) {
// Can't find a better student, so fast break.
break;
}
}
}
if (best != null) {
return best;
}
throw new Exception(...);
要支持所选模块的动态列表和顺序,您可以做的一件事是过滤列表,对其进行排序,然后选择第一个元素:
public static Student filterStudent(List<Student> studentList, List<String> moduleOrder)
throws Exception {
return studentList.stream().filter(s -> moduleOrder.contains(s.getStModule()))
.min(Comparator.comparingInt(student -> moduleOrder.indexOf(student.getSModule())))
.orElseThrow(() -> new Exception("No student found matching criteria"));
}
publicstaticstudent过滤器Student(List studentList,List moduleOrder)
抛出异常{
return studentList.stream().filter(s->moduleOrder.contains(s.getStModule()))
.min(Comparator.comparingInt(student->moduleOrder.indexOf(student.getSModule()))
.orelsetrow(()->新异常(“未找到符合条件的学生”);
}
要执行当前逻辑,您可以使用student list和类似list.of(Module.COMP.getModuleName(),Module.ECON.getModuleName(),Module.AGRI.getModuleName())的调用它作为第二个参数
这将避免列表上的重复迭代。但是我假设moduleOrder
列表很小,有一些元素,如您的示例中所示(它被搜索了几次以进行筛选和排序)将排序(Comparator.comparingit(moduleOrder::indexOf))
而没有映射
ping工作吗?我想你会想在那里使用lambda?谢谢@Naman。我没有编译那个。肯定是一个错误,我现在就纠正。直接使用怎么样?不需要排序。min()
肯定更好@AndyTurner@ernest_k你能用.min
解释一下这行吗。我对它进行了测试,它能工作——但为什么它能工作呢?我喜欢你的第一个解决方案的简单性——它易于阅读和理解。但与其他解决方案和@ernest_k解决方案相比,这对性能的影响有多大。考虑到筛选列表最多为10个元素。
Optional<Student> student = studentList.stream().min(comparator);
Student best = null;
for (Student student : studentList) {
int comp = comparator.compare(best, student);
if (comp > 0) {
best = student;
int studentOrder = studentOrdering.apply(student);
if (studentOrder == 0) {
// Can't find a better student, so fast break.
break;
}
}
}
if (best != null) {
return best;
}
throw new Exception(...);
public static Student filterStudent(List<Student> studentList, List<String> moduleOrder)
throws Exception {
return studentList.stream().filter(s -> moduleOrder.contains(s.getStModule()))
.min(Comparator.comparingInt(student -> moduleOrder.indexOf(student.getSModule())))
.orElseThrow(() -> new Exception("No student found matching criteria"));
}