单次遍历学生列表实现按班级统计数学与英语总分
单次遍历完成班级数学&英语总分统计
当然可以只遍历一次学生列表就完成两门学科的总分统计,核心是让每个班级对应的统计结果同时包含数学和英语的总分,遍历学生时同步更新这两个数值。下面提供几种实现方式:
方式一:自定义统计类(可读性最佳)
先定义一个专门存储两门学科总分的类,方便后续扩展和维护:
class SubjectTotal { int maths; int english; // 合并两个统计结果的方法 public static SubjectTotal merge(SubjectTotal a, SubjectTotal b) { SubjectTotal result = new SubjectTotal(); result.maths = a.maths + b.maths; result.english = a.english + b.english; return result; } }
然后通过一次Stream遍历完成分组统计:
Map<Integer, SubjectTotal> totalPerClass = reportCard.getStudents().stream() .collect(Collectors.groupingBy( Student::getStandard, Collectors.reducing( new SubjectTotal(), // 初始值:两门分数都是0 student -> { SubjectTotal st = new SubjectTotal(); st.maths = student.getMarks().getMaths(); st.english = student.getMarks().getEnglish(); return st; }, SubjectTotal::merge // 合并同一班级的统计结果 ) ));
方式二:使用现成的Entry类(无需额外定义类)
如果不想自定义类,可以用JDK自带的AbstractMap.SimpleEntry来存储两门学科的分数(key存数学,value存英语):
import java.util.AbstractMap; Map<Integer, AbstractMap.SimpleEntry<Integer, Integer>> totalPerClass = reportCard.getStudents().stream() .collect(Collectors.groupingBy( Student::getStandard, Collectors.reducing( new AbstractMap.SimpleEntry<>(0, 0), student -> new AbstractMap.SimpleEntry<>( student.getMarks().getMaths(), student.getMarks().getEnglish() ), (entry1, entry2) -> new AbstractMap.SimpleEntry<>( entry1.getKey() + entry2.getKey(), // 累加数学分数 entry1.getValue() + entry2.getValue() // 累加英语分数 ) ) ));
方式三:使用toMap实现
也可以通过Collectors.toMap来完成,逻辑和上面一致:
Map<Integer, SubjectTotal> totalPerClass = reportCard.getStudents().stream() .collect(Collectors.toMap( Student::getStandard, // 分组键:班级 student -> { SubjectTotal st = new SubjectTotal(); st.maths = student.getMarks().getMaths(); st.english = student.getMarks().getEnglish(); return st; }, SubjectTotal::merge // 重复班级时合并统计结果 ));
以上三种方式都只需要遍历一次学生列表,就能同时完成两门学科的班级总分统计,相比原来两次遍历的写法更高效。
内容的提问来源于stack exchange,提问作者astar
相关产品推荐
相关产品推荐

