首页 > 解决方案 > 使用 Java 流的学生的平均分

问题描述

给定一个学生班级,我需要使用 Java 8 流 API 查找所有名字以“A”开头的学生,按照他们的平均分数排序。

我试过下面的代码。问题是我可以很容易地通过过滤找出名字以“A”开头的学生,但是我如何找出平均分(因为我的分数存储在一个列表中——它有科目和分数)。另外我如何订购它们?这两个问题我完全一无所知。

下面是代码

public class Marks {

    private String subject; 
    private int score;

// constructors ....
// getter and setters..
}

…和:

public class Student {
    
    private String name; 
    private int id; 
    private List<Marks> marks;

// constructors..
// getters and setters. 

}

…和:

public class StudentMarks {

    public static void main(String[] args) {
        String name = null; 
        int id = 0; 
        
        int numberOfSubjects = 0;
        String subject = null; 
        int score = 0;
        
        List<Student> students = new ArrayList<Student>();
        List<Marks> marks = new ArrayList<Marks>();         
        
        for(int i = 0; i < numberOfStudents; i++) {
            Student student = new Student();
            
            // code here to enter the name, id and number of subjects
            
            for(int j = 0; j < numberOfSubjects; j++) {
                Marks m = new Marks();
                
                // code to take the subject and score of the student..
                
                m.setSubject(subject);
                m.setScore(score);      
                
                marks.add(m); 
            }
            
            student.setName(name);
            student.setId(id);  
            student.setMarks(marks);
            
            students.add(student);
        }
        
        // This would filter out the students whose name starts with 'A'
        List<Student> names = students.stream().filter(n -> n.getName().startsWith("A")).collect(Collectors.toList());
        
        // Now second step (basically all this is to be done in one step) is to get the average marks and that too in some order (either ascending or descending. How do I do this ???
       OptionalDouble averageMarks = students.stream().filter(n -> n.getName().startsWith("A")).mapToDouble(s -> s.getMarks().get(0).getScore()).average(); 
       
        // I can't have get(0) above   
       //  How do I use mapToDouble to get the average as marks are stored in a list which has subject and score. I need to get the sum and then average for all students and then order them 
       // How do I use mapToDouble to sum the marks for each student and then get an average and then order them (ascending / descending).
    }
}

标签: javajava-stream

解决方案


我用 getter 和 setter 创建了类。额外的学生将显示过滤正在工作。这是我将如何做到的。

List<Student> list = new ArrayList<>();
List<Marks> m1 = List.of(new Marks("English", 100),
        new Marks("Algebra", 94));
List<Marks> m2 = List.of(new Marks("English", 88),
        new Marks("Calculus", 97));

List<Student> students = List.of(new Student("Amy", 1, m1),
        new Student("Allen", 2, m2),
        new Student("Bob", 3, m1),
        new Student("John", 4, m2));

这是流式处理。

  • 字母上的第一个过滤器A
  • 然后,构建一个TreeMap,键是学生的平均值,值是名称。
  • 平均值来自 summarystatics 方法。
Map<Double, String> averages = students.stream()
        .filter(s -> s.getName().startsWith("A"))
        .collect(Collectors.toMap(
                s -> s.getMarks().stream()
                        .mapToInt(Marks::getScore)
                        .summaryStatistics().getAverage(), s->s.getName(),
                        (a,b)->a, // merge, not used by syntactically required.
                ()->new TreeMap<>(Comparator.reverseOrder())
                ));

averages.forEach((k,v)->System.out.printf("Student: %8s,   Average: %s%n", v,k));

印刷

Student:      Amy,   Average: 97.0
Student:    Allen,   Average: 92.5

如果您希望平均值按升序排列,只需从 TreeMap 中删除 Comparator。


推荐阅读