Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Java 8过滤具有多个条件的流,直到结果不为空_Java_Arraylist_Filter_Java 8_Enums - Fatal编程技术网

使用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"));
}