使用Java8流获取最大平均主题分数

使用Java8流获取最大平均主题分数,java,java-8,code-snippets,Java,Java 8,Code Snippets,我的班级学生如下 class Student{ Map<String,Integer> subjectMarks; String name; public Student(Map<String,Integer> subject, String name) { super(); this.subjectMarks = subject;

我的班级学生如下

 class Student{
        Map<String,Integer> subjectMarks;
        String name;
        
        
        public Student(Map<String,Integer> subject, String name) {
            super();
            this.subjectMarks = subject;
            this.name = name;
        }
        public Map<String,Integer> getSubjectMarks() {
            return subjectMarks;
        }
        public void setSubjectMarks(Map<String,Integer> subject) {
            this.subjectMarks = subject;
        }
        
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
     }
班级学生{
地图主题标记;
字符串名;
公立学生(地图主题、字符串名称){
超级();
this.subjectMarks=主题;
this.name=名称;
}
公共地图getSubjectMarks(){
返回主题标记;
}
公共无效设置主题标记(地图主题){
this.subjectMarks=主题;
}
公共字符串getName(){
返回名称;
}
公共void集合名(字符串名){
this.name=名称;
}
}
在main方法中,我们在arraylist中添加student对象,如下所示

        ArrayList<Student> arr = new ArrayList<Student>();
        Map m1 = new HashedMap();
        m1.put("Maths",40);
        m1.put("Science",50);
        Map m2 = new HashedMap();
        m2.put("Maths",60);
        m2.put("Science",20);
        arr.add(new Student(m1, "RAJ"));
        arr.add(new Student(m2, "AMIT"));
ArrayList arr=new ArrayList();
Map m1=新的HashedMap();
m1.put(“数学”,40);
m1.put(“科学”,第50页);
Map m2=新的HashedMap();
m2.put(“数学”,60);
m2.put(“科学”,第20页);
arr.add(新学生(m1,“RAJ”);
arr.add(新学员(m2,“AMIT”);

可以帮助/指导我找出每个学生学科的平均分数,然后从平均分数中获得最大分数。我想帮助您在java8中编写这段代码,但不要局限于java8中的流,您必须将流结果直接处理到下一个流中,以此类推。。。效率可能不是最好的,但是考虑嵌套循环。

开始想想你有什么:每个
学生都有几分。您希望找到每个
学生的这些分数的平均值。您可以将问题简化为首先考虑如何获得一名
学生的平均数

double average = student.getSubjectMarks().values().stream()
        .mapToInt(Integer::valueOf).average().orElse(0.0);
即使示例仅显示整数,平均值也可以是浮点数

然后,您必须遍历所有学生,并为每个学生执行上述过程

Map<String, Double> studentAverages = new HashMap<>();

arr.forEach(student -> {
    double average = student.getSubjectMarks().values().stream()
            .mapToInt(Integer::valueOf).average().orElse(0.0);
    studentAverages.put(student.getName(), average);
});

一些答案提供了更复杂的流用法。但是,上面的代码更具可读性。此外,数据类型
对象
非常通用,难以进一步使用,并且容易出错。

正如@Felix在他的回答中所指出的,因为您有一个嵌套的集合,所以很难在单个流中处理。您可以使用一个流计算每个学生的平均值,另一个流计算平均值的最大值

从一个单独的函数开始计算学生的平均值:

private option双计算标记(学生){
返回student.getSubjectMarks().values().stream()
.mapToInt(整数::intValue)
.average();
}
请注意,如果要返回
双精度
,可以将
.orElse(0.0)
(或其他值)添加到管道中,但这不允许您稍后区分所有0的学生和未注册任何科目的学生

然后你可以把平均值收集到地图上

Map averageMarks=arr.stream()
.collect(Collectors.toMap(Student::getName,this::calculateAverageMarks));
请注意,如果两个学生共享相同的名称,则在收集器中使用
Student::getName
,将抛出。您可以使用
Function.identity()
来确保每个键都是不同的,只要您不覆盖
Student
中的
equals

double average = student.getSubjectMarks().values().stream()
        .mapToInt(Integer::valueOf).average().orElse(0.0);
如果你愿意,你可以删除没有科目的学生

averageMarks.values().removeIf(v->!v.isPresent());
在Java11中,您可以使用
OptionalDouble::isEmpty
代替lambda

然后,您可以将这些值映射到一个双流,并获得最大值

optionalduble max=averageMarks.values().stream()
.filter(OptionalDouble::isPresent)//如果您没有删除空标记
.mapToDouble(可选Double::getAsDouble)
.max();

按照您的要求使用streams来解决这个问题没有错

  • 流式处理地图列表
  • 将学生姓名和平均值放入对象数组中。
    • 流化映射的值,并使用summaryStatistics获得平均值
  • 然后使用带有比较器的maxBy获得最大平均值
  • 然后显示它
印刷品

[RAJ, 45.0]

        

最好在输出中包含您想要的内容。以你的例子来说,你想让RAJ得到45分,AMIT得到40分,还是数学得到50分,科学得到35分?将你的尝试和你被困的地方包括在内也很有帮助,特别是因为这看起来像是一个家庭作业。预期的输出是RAJ 45和Amit 40,然后从两者中获得最大平均分数,即45。我试图获得输出,我知道下面的代码将根据主题名给你平均分数
Map average=arr.stream().Map(s->s.getSubjectMarks()).flatMap(m->m.entrySet().stream()).collect(Collectors.groupingBy(Entry::getKey,Collectors.averagingDouble(Entry::getValue));
我想得到每个学生名字的平均分数感谢Felix的知识。对于其他问题,请记住您的建议:-)
[RAJ, 45.0]