You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Java Stream API按科目筛选成绩前三的学生

Java Stream API按科目筛选成绩前三的学生

嘿,看起来你已经走对方向了!分组科目这一步已经完成,接下来只需要给每个分组加上按成绩降序排序和截取前3名的逻辑就行。我来给你一步步拆解怎么实现:

核心思路

  1. 用flatMap把每个学生的科目列表展开成单个的Subject流(你已经做到啦)
  2. 按科目名称分组,同时对每个分组内的Subject对象按分数从高到低排序
  3. 对排序后的分组列表,只保留前3个元素,就是该科目成绩前三的学生

完整实现代码

把你原来的studentMap代码替换成下面这段,并且可以加上结果打印的逻辑:

// 按科目分组,每组内按成绩降序排序后取前3
Map<String, List<Subject>> topStudentsBySubject = studentList.stream()
        .flatMap(student -> student.getSubjectList().stream())
        .collect(Collectors.groupingBy(
                Subject::getSubjectName,
                Collectors.collectingAndThen(
                        Collectors.toList(),
                        list -> list.stream()
                                .sorted(Comparator.comparingDouble(Subject::getMarks).reversed())
                                .limit(3)
                                .collect(Collectors.toList())
                )
        ));

// 打印结果,清晰展示每个科目前三的学生
topStudentsBySubject.forEach((subjectName, topStudents) -> {
    System.out.println("=== " + subjectName + " 成绩前三的学生 ===");
    topStudents.forEach(subject -> {
        // 根据学生ID找到对应的学生信息
        Student student = studentList.stream()
                .filter(s -> s.getStudentId().equals(subject.getStudentId()))
                .findFirst()
                .orElse(null);
        if (student != null) {
            System.out.printf("学生ID: %d, 姓名: %s, %s成绩: %.1f%n",
                    student.getStudentId(), student.getName(), subjectName, subject.getMarks());
        }
    });
    System.out.println();
});

代码解释

  • Collectors.groupingBy(Subject::getSubjectName, ...):第一个参数是分组的键(科目名称),第二个参数是下游收集器,用来处理每个分组的元素
  • Collectors.collectingAndThen(...):这个收集器可以先把元素收集成列表,然后对列表做进一步处理——这里就是先排序,再取前3
  • sorted(Comparator.comparingDouble(Subject::getMarks).reversed()):按分数降序排序,reversed()是把默认的升序改成降序
  • limit(3):只保留排序后的前3个元素,也就是成绩最高的三个

小优化建议

你现在的Subject类里存了studentId,要关联学生信息还得再查一遍列表。如果想更高效,可以在Subject里直接持有Student对象的引用,这样打印的时候就不用额外查询啦,代码会更简洁。

比如修改Subject类:

class Subject{
    private Student student; // 直接关联Student对象
    private String subjectName;
    private Double marks;

    // 构造方法、getter/setter、toString都对应修改
    public Subject(Student student, String subjectName, Double marks) {
        this.student = student;
        this.subjectName = subjectName;
        this.marks = marks;
    }
}

这样创建Subject的时候直接传入Student对象,后续打印就可以直接从Subject里获取学生信息啦。

备注:内容来源于stack exchange,提问作者Sanjay Naik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:18:02