Java Streams实现各任务平均分计算及最高均分任务查询
Java Streams 实现课程任务分数统计方法
仅可修改指定两个方法的实现逻辑,其余已有代码无需改动。
待实现方法要求
averageScoresPerTask:接收Stream<CourseResult>类型入参,返回Map<String, Double>类型结果,存储每个任务名称对应的平均得分,方法签名固定:
public Map<String, Double> averageScoresPerTask(Stream<CourseResult> results) {}
easiestTask:接收Stream<CourseResult>类型入参,返回String类型结果,对应平均得分最高的任务名称,方法签名固定:
public String easiestTask(Stream<CourseResult> results) {}
已有依赖代码
CourseResult 类定义
public class CourseResult { private final Person person; private final Map<String, Integer> taskResults; public CourseResult(final Person person, final Map<String, Integer> taskResults) { this.person = person; this.taskResults = taskResults; } public Person getPerson() { return person; } public Map<String, Integer> getTaskResults() { return taskResults; } }
测试数据生成逻辑
内置两个测试流生成方法,分别生成编程课、历史课的课程结果流,单批次生成的结果数量可通过.limit()参数调整,计算平均分时禁止硬编码除数为固定值,必须适配任意数量的输入结果:
private final String[] programTasks = {"Lab 1. Figures", "Lab 2. War and Peace", "Lab 3. File Tree"}; private final String[] practicalHistoryTasks = {"Shieldwalling", "Phalanxing", "Wedging", "Tercioing"}; private Stream<CourseResult> programmingResults(final Random random) { int n = random.nextInt(names.length); int l = random.nextInt(lastNames.length); return IntStream.iterate(0, i -> i + 1) .limit(3) .mapToObj(i -> new Person( names[(n + i) % names.length], lastNames[(l + i) % lastNames.length], 18 + random.nextInt(20))) .map(p -> new CourseResult(p, Arrays.stream(programTasks).collect(toMap( task -> task, task -> random.nextInt(51) + 50)))); } private Stream<CourseResult> historyResults(final Random random) { int n = random.nextInt(names.length); int l = random.nextInt(lastNames.length); AtomicInteger t = new AtomicInteger(practicalHistoryTasks.length); return IntStream.iterate(0, i -> i + 1) .limit(3) .mapToObj(i -> new Person( names[(n + i) % names.length], lastNames[(l + i) % lastNames.length], 18 + random.nextInt(20))) .map(p -> new CourseResult(p, IntStream.iterate(t.getAndIncrement(), i -> t.getAndIncrement()) .map(i -> i % practicalHistoryTasks.length) .mapToObj(i -> practicalHistoryTasks[i]) .limit(3) .collect(toMap( task -> task, task -> random.nextInt(51) + 50)))); }
实现代码
import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; public Map<String, Double> averageScoresPerTask(Stream<CourseResult> results) { // Stream为一次性资源,先收集为列表同时获取总记录数,避免流复用报错 List<CourseResult> resultList = results.collect(Collectors.toList()); long totalStudentCount = resultList.size(); // 空流直接返回空Map if (totalStudentCount == 0) { return Collections.emptyMap(); } // 拍平所有任务分数条目,按任务名分组累加总分后计算平均值 return resultList.stream() // 调用getTaskResults().entrySet()即可访问所有任务名、对应分数的键值对 .flatMap(courseResult -> courseResult.getTaskResults().entrySet().stream()) .collect(Collectors.groupingBy( Map.Entry::getKey, Collectors.summingDouble(Map.Entry::getValue) )) .entrySet() .stream() .collect(Collectors.toMap( Map.Entry::getKey, scoreEntry -> scoreEntry.getValue() / totalStudentCount )); } public String easiestTask(Stream<CourseResult> results) { // 复用平均分计算逻辑,直接取平均分最高的任务名 return averageScoresPerTask(results) .entrySet() .stream() .max(Map.Entry.comparingByValue()) .map(Map.Entry::getKey) .orElse(null); }
实现说明
- 不需要硬编码除数为3,总人数通过收集后的列表长度动态获取,完全适配测试数据生成方法中
.limit()参数的调整 - 聚合分数时使用
summingDouble做累加,避免整数除法导致的精度丢失 easiestTask直接复用平均分计算逻辑,减少重复代码,后续规则调整时只需要修改一处逻辑
内容的提问来源于stack exchange,提问作者fireballun
相关产品推荐
相关产品推荐

