【问题标题】:Get maximum of average subject marks using java 8 stream使用 java 8 流获得最大平均科目分数
【发布时间】:2021-03-31 15:27:18
【问题描述】:

我的同学如下

 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;
        }
     }

在main方法中,我们在arraylist中添加学生对象如下。

        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"));

可以帮助/指导我找到每个学生的平均科目分数,然后从平均分数中获得最高分。我需要帮助在 java8 中编写这个 sn-p

【问题讨论】:

  • 最好在输出中包含您要查找的内容。使用您的示例,您想要 RAJ 45 分和 AMIT 40 分,还是您想要数学 50 分和科学 35 分?将您的尝试包括到远方和卡住的地方也很有帮助,尤其是因为这看起来像是一项家庭作业。
  • 预期输出为 RAJ 45 和 Amit 40,然后从两者中获得最大平均分数,这将是 45。
  • 我试图得到输出我知道下面的代码会给你按主题名称的平均值Map&lt;String, Double&gt; average= arr.stream().map(s -&gt; s.getSubjectMarks()).flatMap(m -&gt; m.entrySet().stream()).collect(Collectors.groupingBy(Entry::getKey, Collectors.averagingDouble(Entry::getValue)));我想得到每个学生姓名的平均分数

标签: java java-8 code-snippets


【解决方案1】:

不要将自己局限于 Java 8 中的流的想法,您必须将流结果直接处理到下一个流中等等......效率可能不是最好的,但可以考虑嵌套循环。

开始思考你拥有什么:每个Student 获得几个分数。您想找到每个Student 的这些标记的平均值。您可以将问题简化为首先考虑如何获得一个Student 的平均值。

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);
});

在所描述的实现中,所需的平均值保存在Map studentAverages 中,其中学生的姓名作为键,平均分作为值。

然后您可以简单地从列表中获取最大整数。

studentAverages.values().stream().mapToDouble(Double::doubleValue).max();

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

【讨论】:

  • 感谢菲利克斯的知识。会记住您对其他问题的建议:-)
【解决方案2】:

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

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

private OptionalDouble calculateAverageMarks(Student student) {
    return student.getSubjectMarks().values().stream()
        .mapToInt(Integer::intValue)
        .average();
}

请注意,如果您想返回 double,您可以将 .orElse(0.0)(或其他值)添加到管道中,但这不允许您稍后区分全 0 的学生和未注册的学生任何科目。

然后您可以将平均值收集到地图中。

Map<String, OptionalDouble> averageMarks = arr.stream()
    .collect(Collectors.toMap(Student::getName, this::calculateAverageMarks));

请注意,如果两个学生同名,则在收集器中使用 Student::getName 会抛出异常。您可以改用Function.identity() 来确保每个键都是不同的,只要您不覆盖Student 中的equals

如果需要,您可以删除没有科目的学生

averageMarks.values().removeIf(v -> !v.isPresent());

在 Java 11 中,您可以使用 OptionalDouble::isEmpty 代替 lambda。

然后您可以将值映射到双流并获取最大值

OptionalDouble max = averageMarks.values().stream()
    .filter(OptionalDouble::isPresent) // In case you didn't remove the empty marks
    .mapToDouble(OptionalDouble::getAsDouble)
    .max();

【讨论】:

    【解决方案3】:

    按照您的要求使用流来解决这个问题没有任何问题。

    • 流式传输地图列表。
    • 将学生姓名和平均值放入对象数组中。
      • 流式传输地图的值并使用 summaryStatistics 获取平均值。
    • 然后将 maxBy 与比较器一起使用以获得最大平均值。
    • 然后显示它。
    Object[] result = arr.stream().map(s -> new Object[] {
            s.getName(),
            s.getSubjectMarks().values().stream()
                    .mapToInt(Integer::valueOf)
                    .summaryStatistics().getAverage() })
            .max(Comparator.comparing(obj -> (double) obj[1]))
            .get();
    
    System.out.println(Arrays.toString(result));
    

    打印

    [RAJ, 45.0]
    
            
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多