简体   繁体   English

Java 获取 Arraylist 中某些元素的平均值

[英]Java getting the average of some elements in an Arraylist

I'm new to Java and I'm writting a program that manages students, their subjects and the grades in that subject.我是 Java 的新手,我正在编写一个程序来管理学生、他们的科目和该科目的成绩。

The code asks for the details of the student and then it saves all to an Arraylist.该代码询问学生的详细信息,然后将所有信息保存到 Arraylist。 I'm trying to get the average grade of a subject without success, I've already calculated the average grade of a certain student, but getting all the grades from certain subject and then calculating the average is beyond my comprehension.我试图获得一个科目的平均成绩,但没有成功,我已经计算了某个学生的平均成绩,但是得到某个科目的所有成绩然后计算平均成绩超出了我的理解范围。

This is the code I used for the creation of the Arraylist:这是我用于创建 Arraylist 的代码:

public class options {

public String name;

public ArrayList<students> studentlist = new ArrayList<students>(10);  

    public String createstudent(String name, String subject, Float rade1, Float grade2, Float grade3) {
        studentlist.add(new students(name, subject, grade1, grade2, grade3);
        return "The student has been added to the database. ";
    }
}

And this is the code of the student class:这是学生class的代码:

public class students{
    
    public String name;
    public String subject;
    public Float grade1;  
    public Float grade2;  
    public Float grade3;
    
   public students(String name, String subject, Float grade1, Float grade2, Float grade3) {
        
        this.name= name;
        this.subject= subject;
        this.grade1= grade1;
        this.grade2= grade2;
        this.grade3= grade3;
    }
}   

I've tried something like我试过类似的东西

public double getAverageValue(){
  double averageValue = 0;
  double sum = 0;

  if(studentlist.size() > 0){
    for ( int i=0; i < studentlist.size() ; i++) {
      sum += studentlist.get(i).getname().getgrade1().getgrade2().getgrade3();
    }
    averageValue = (sum / (double)studentlist.size())
  }

  return averageValue;
}

But I don't know how to select only the grades from a certain subject and not all the grades from all the students, so I'm kinda stuck.但我不知道如何 select 只有某个学科的成绩,而不是所有学生的所有成绩,所以我有点卡住了。

EDIT:编辑:

Based on the answers here and some of what I already done, this is the final code:根据此处的答案和我已经完成的一些工作,这是最终代码:

public String showAverageGrade(String clase){
        int countstudents =0;
        double studentaverage =0;

        for(int i=0 ; i < studentlist.size();i++){
            if(studentlist.get(i).asksubject().equals(subject)){
                studentaverage +=studentlist.get(i).studentaverage ();
                countstudents++;

            }
        }
        return "The average grade of " + subject + " is " + (studentaverage / countstudents) + ".";

    }  

English isn't my first language, so any mistake is because I translated it.英语不是我的第一语言,所以任何错误都是因为我翻译了它。

Thanks everyone for your feedback.感谢大家的反馈。

The right way to architect this is first, you need to abstract Student as a Class.构建这个的正确方法是首先,您需要将 Student 抽象为 Class。 The simple way is in the main class you create a array attribute students, in the Student class it will have an attribute Map called subjects to put a key (Subject name) and the value (Grade).简单的方法是在主 class 你创建一个数组属性学生,在学生 class 它将有一个属性 Map 称为科目放一个键(科目名称)和值(等级)。

If I understand correctly you need to put some students in the main array, their grades, then calculate the average of all these students per subject, to calculate this you will need to create another Map and interact by key(Subject) sum all occurrences, then split by the count.如果我理解正确,您需要将一些学生放在主数组中,即他们的成绩,然后计算每个科目所有这些学生的平均值,要计算这个,您需要创建另一个 Map 并按键交互(主题)总和所有出现,然后按计数拆分。

In the simple way you already knows all subjects types, if you not know, it will be more complex, before calculate you need another List without duplicated types to filter and interact, maybe a way to create this new list without duplicated is explained here: https://www.baeldung.com/java-remove-duplicates-from-list .简单来说,你已经知道所有的主题类型,如果你不知道,它会更复杂,在计算之前你需要另一个没有重复类型的列表来过滤和交互,也许这里解释了一种创建这个没有重复的新列表的方法: https://www.baeldung.com/java-remove-duplicates-from-list

Your way你的方式

Using your code, presumably each of your three grades by position represent three different courses.使用您的代码,position 的三个等级中的每一个大概代表三个不同的课程。 I assume you put all the grades for "French" class in grade1 field, grades for "Composition" class in grade2 field, and grades for "Math" class in grade3 .我假设您将“法语” grade1的所有成绩放在第 1 级字段中,将“作文”class 的成绩放在第grade2级字段中,将“数学” grade3的成绩放在第 3 级字段中

So loop the students, pulling each grade separately.所以循环学生,分别拉每个年级。

float frenchPoints = 0 ;
float compositionPoints = 0 ;
float mathPoints = 0 ;
for( Student student : students )
{
    frenchPoints = ( frenchPoints + student.getGrade1() ) ;
    compositionPoints = ( compositionPoints + student.getGrade2() ) ;
    mathPoints = ( mathPoints + student.getGrade3() ) ;
}

Divide points by the number of grades to render an average.用分数除以分数以得出平均值。

Do not divide a float (fractional number) by an int (integer) if you want a float result.如果您想要float结果,请不要将float (小数)除以int (整数)。 So we must cast our int to a float before doing the division.所以我们必须在进行除法之前将我们的int转换为float

float frenchAverage = ( frenchPoints / (float) students.size() ) ;
…

My way我的方式

As suggested in the Answer by Bruno Souza Picinini , in a more realistic scenario, you would break out the data into separate classes.正如Bruno Souza Picinini 的回答中所建议的那样,在更现实的情况下,您可以将数据分解为单独的类。 Likely you would represent Student in a class, which in turn might contain a collection of objects of a CourseGrade class.您可能会在 class 中代表Student ,该 class 又可能包含CourseGrade class 的对象集合。

In Java 16 we can use the new records feature to briefly write a class whose main purpose is to transparently and immutably communicate data.在 Java 16 中,我们可以使用新的记录功能简要编写一个 class,其主要目的是透明和不可变地传输数据。 The compiler implicitly creates the constructor, getters, equals & hashCode , and toString .编译器隐式创建构造函数、getter、 equals & hashCodetoString

public record CourseGrade(String courseName , YearMonth term , Float grade) {}
public record Student(UUID id , String name , Set < CourseGrade > courseGrades) {}

Let's get some example data.让我们获取一些示例数据。

private List < Student > fetchStudents ( )
{
    List < Student > students =
            List.of(
                    new Student( UUID.fromString( "57ce6790-5094-480c-88f5-79ee9e59b9bb" ) , "Alice" ,
                            Set.of(
                                    new CourseGrade( "French" , YearMonth.of( 2021 , Month.JANUARY ) , 3.2F ) ,
                                    new CourseGrade( "French" , YearMonth.of( 2021 , Month.APRIL ) , 3.6F ) ,
                                    new CourseGrade( "Composition" , YearMonth.of( 2021 , Month.JANUARY ) , 3.3F ) ,
                                    new CourseGrade( "Composition" , YearMonth.of( 2021 , Month.APRIL ) , 3.7F )
                            )
                    ) ,
                    new Student( UUID.fromString( "3ed40f58-fb82-44f0-9ae8-7cc1b317085e" ) , "Bob" ,
                            Set.of(
                                    new CourseGrade( "French" , YearMonth.of( 2021 , Month.JANUARY ) , 2.7F ) ,
                                    new CourseGrade( "French" , YearMonth.of( 2021 , Month.APRIL ) , 2.6F ) ,
                                    new CourseGrade( "Composition" , YearMonth.of( 2021 , Month.JANUARY ) , 2.9F ) ,
                                    new CourseGrade( "Composition" , YearMonth.of( 2021 , Month.APRIL ) , 2.7F )
                            )
                    ) ,
                    new Student( UUID.fromString( "9058567e-8a5e-4606-81b0-1def2bb8ceb5" ) , "Carol" ,
                            Set.of(
                                    new CourseGrade( "French" , YearMonth.of( 2021 , Month.JANUARY ) , 3.0F ) ,
                                    new CourseGrade( "French" , YearMonth.of( 2021 , Month.APRIL ) , 3.1F ) ,
                                    new CourseGrade( "Composition" , YearMonth.of( 2021 , Month.JANUARY ) , 3.2F ) ,
                                    new CourseGrade( "Composition" , YearMonth.of( 2021 , Month.APRIL ) , 3.4F )
                            )
                    )
            );
    return students;
}

Write a method to report the average grade for a particular course name for a particular term.编写一个方法来报告特定学期特定课程名称的平均成绩。

We report an Optional because it is possible we might be asking for a course in a term when no such class offering was made.我们报告了一个Optional课程,因为我们可能会在没有提供此类 class 课程的情况下要求一门课程。 So if no class, then no students earned any grades.因此,如果没有 class,则没有学生获得任何成绩。 So rather than report a number we want to report an empty Optional object.因此,我们不想报告一个数字,而是报告一个空的Optional object。 If a course was offered in that term with students enrolled, then we return an Optional containing a Float object for the number of the average grade.如果在该学期提供了一个有学生注册的课程,那么我们返回一个Optional ,其中包含一个Float object 作为平均成绩的数量。

By the way, be aware that floating-point types such as float / Float trade away inaccuracy for speed of execution.顺便说一句,请注意浮点类型(例如float / Float )以不准确性换取执行速度 If you care about accuracy, use BigDecimal class instead.如果您关心准确性,请改用BigDecimal class。

private Optional < Float > reportAverageGradePerCourseInTerm ( String courseName , YearMonth term )
{
    Objects.requireNonNull( courseName );
    Objects.requireNonNull( term );
    List < CourseGrade > courseGrades = new ArrayList <>( this.students.size() );
    for ( Student student : this.students )
    {
        for ( CourseGrade courseGrade : student.courseGrades() )
        {
            if ( courseGrade.courseName().equals( courseName ) && courseGrade.term().equals( term ) )
            {
                courseGrades.add( courseGrade ); // If a match on name and term, remember this `CourseGrade` object. Else, forget/skip.
            }
        }
    }
    if ( courseGrades.size() == 0 ) { return Optional.empty(); }
    float totalPoints = 0F;
    for ( CourseGrade courseGrade : courseGrades )
    {
        totalPoints = totalPoints + courseGrade.grade();
    }
    Float average = ( totalPoints / ( float ) courseGrades.size() );
    return Optional.of( average );
}

Pull all that code into a class App with a main method to drive a demonstration.使用main方法将所有代码拉入 class App以驱动演示。

package work.basil.example.reportcard;

import java.time.Month;
import java.time.YearMonth;
import java.util.*;

public class App
{
    public static void main ( String[] args )
    {
        App app = new App();
        app.students = app.fetchStudents();
        System.out.println( "app.students = " + app.students );
        Optional < Float > averageForFrenchIn2021_01 = app.reportAverageGradePerCourseInTerm( "French" , YearMonth.of( 2021 , Month.JANUARY ) );
        System.out.println( "averageForFrenchIn2021_01 = " + averageForFrenchIn2021_01 );
    }

    // Member fields
    List < Student > students;

    // Logic

    private List < Student > fetchStudents ( )
    {
        List < Student > students =
                List.of(
                        new Student( UUID.fromString( "57ce6790-5094-480c-88f5-79ee9e59b9bb" ) , "Alice" ,
                                Set.of(
                                        new CourseGrade( "French" , YearMonth.of( 2021 , Month.JANUARY ) , 3.2F ) ,
                                        new CourseGrade( "French" , YearMonth.of( 2021 , Month.APRIL ) , 3.6F ) ,
                                        new CourseGrade( "Composition" , YearMonth.of( 2021 , Month.JANUARY ) , 3.3F ) ,
                                        new CourseGrade( "Composition" , YearMonth.of( 2021 , Month.APRIL ) , 3.7F )
                                )
                        ) ,
                        new Student( UUID.fromString( "57ce6790-5094-480c-88f5-79ee9e59b9bb" ) , "Bob" ,
                                Set.of(
                                        new CourseGrade( "French" , YearMonth.of( 2021 , Month.JANUARY ) , 2.7F ) ,
                                        new CourseGrade( "French" , YearMonth.of( 2021 , Month.APRIL ) , 2.6F ) ,
                                        new CourseGrade( "Composition" , YearMonth.of( 2021 , Month.JANUARY ) , 2.9F ) ,
                                        new CourseGrade( "Composition" , YearMonth.of( 2021 , Month.APRIL ) , 2.7F )
                                )
                        ) ,
                        new Student( UUID.fromString( "57ce6790-5094-480c-88f5-79ee9e59b9bb" ) , "Carol" ,
                                Set.of(
                                        new CourseGrade( "French" , YearMonth.of( 2021 , Month.JANUARY ) , 3.0F ) ,
                                        new CourseGrade( "French" , YearMonth.of( 2021 , Month.APRIL ) , 3.1F ) ,
                                        new CourseGrade( "Composition" , YearMonth.of( 2021 , Month.JANUARY ) , 3.2F ) ,
                                        new CourseGrade( "Composition" , YearMonth.of( 2021 , Month.APRIL ) , 3.4F )
                                )
                        )
                );
        return students;
    }

    private Optional < Float > reportAverageGradePerCourseInTerm ( String courseName , YearMonth term )
    {
        Objects.requireNonNull( courseName );
        Objects.requireNonNull( term );
        List < CourseGrade > courseGrades = new ArrayList <>( this.students.size() );
        for ( Student student : this.students )
        {
            for ( CourseGrade courseGrade : student.courseGrades() )
            {
                if ( courseGrade.courseName().equals( courseName ) && courseGrade.term().equals( term ) )
                {
                    courseGrades.add( courseGrade ); // If a match on name and term, remember this `CourseGrade` object. Else, forget/skip.
                }
            }
        }
        if ( courseGrades.size() == 0 ) { return Optional.empty(); }
        float totalPoints = 0F;
        for ( CourseGrade courseGrade : courseGrades )
        {
            totalPoints = totalPoints + courseGrade.grade();
        }
        Float average = ( totalPoints / ( float ) courseGrades.size() );
        return Optional.of( average );
    }
}

When main is run.main运行时。

app.students = [Student[id=57ce6790-5094-480c-88f5-79ee9e59b9bb, name=Alice, courseGrades=[CourseGrade[courseName=French, term=2021-04, grade=3.6], CourseGrade[courseName=French, term=2021-01, grade=3.2], CourseGrade[courseName=Composition, term=2021-01, grade=3.3], CourseGrade[courseName=Composition, term=2021-04, grade=3.7]]], Student[id=57ce6790-5094-480c-88f5-79ee9e59b9bb, name=Bob, courseGrades=[CourseGrade[courseName=French, term=2021-04, grade=2.6], CourseGrade[courseName=French, term=2021-01, grade=2.7], CourseGrade[courseName=Composition, term=2021-01, grade=2.9], CourseGrade[courseName=Composition, term=2021-04, grade=2.7]]], Student[id=57ce6790-5094-480c-88f5-79ee9e59b9bb, name=Carol, courseGrades=[CourseGrade[courseName=French, term=2021-04, grade=3.1], CourseGrade[courseName=Composition, term=2021-01, grade=3.2], CourseGrade[courseName=Composition, term=2021-04, grade=3.4], CourseGrade[courseName=French, term=2021-01, grade=3.0]]]]
averageForFrenchIn2021_01 = Optional[2.9666665]

That looks correct, the average of ( 3.2, 2.7, 3.0 ) is 2.96….看起来是正确的,( 3.2, 2.7, 3.0 ) 的平均值是 2.96…。

These solutions enable you to type in a grade for every student in every subject and then output the average in all subjects graded.这些解决方案使您可以输入每个学生在每个科目中的成绩,然后输入所有科目评分的平均值。

Add every class as an own file in your folder.将每个 class 作为自己的文件添加到您的文件夹中。

We represent a subject with SchoolSubject.java:我们用 SchoolSubject.java 表示一个主题:

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

//abstract class. is init from sub classes
public abstract class SchoolSubjects {

//grades in a subject
protected List<Grade> studentGrades;
Scanner myInput = new Scanner(System.in);

abstract double getAverageValue();

abstract void gradeStudents(List<Student> students) throws IOException;

public SchoolSubjects() {
    this.studentGrades = new ArrayList<>();
}
}

Then we create a class for each subject:然后我们为每个主题创建一个 class:

import java.io.IOException;
import java.util.List;

public class EnglishSubject extends SchoolSubjects {

//constructor
public EnglishSubject() {
    super();
}

//Overrides method in super class
@Override
double getAverageValue() {
    double sum = 0;
    if (!studentGrades.isEmpty()) {
        for (Grade grade : studentGrades) {

            sum += grade.getGrade();
        }
        return sum / studentGrades.size();
    }
    return sum;
}


//Overrides method in super class
//parameter: List of students to be graded.
//Takes console input for grade.
//generates random name to represent student
@Override
void gradeStudents(List<Student> students) throws IOException {
    System.out.println("Grade for english subject");
    for (Student student : students) {
        System.out.print("Student:" + " " + RandomNames.randomIdentifier() + " " + 
"Enter grade: ");
        double grade = myInput.nextDouble();
        studentGrades.add(new Grade(grade, student));
    }
}
}

Another subject with same methods.用同样方法的另一个主题。 Keep in mind that the methods can be changed in each subject because of inheritance:请记住,由于 inheritance,可以在每个主题中更改方法:

import java.io.IOException;
import java.util.List;

public class MathSubject extends SchoolSubjects {

//constructor
public MathSubject() {
    super();
}

//Overrides method in super class
@Override
double getAverageValue() {
    double sum = 0;
    if (!studentGrades.isEmpty()) {
        for (Grade grade : studentGrades) {

            sum += grade.getGrade();
        }
        return sum / studentGrades.size();
    }
    return sum;
}

//Overrides method in super class
//parameter: List of students to be graded.
//Takes console input for grade.
//generates random name to represent student
@Override
void gradeStudents(List<Student> students) throws IOException {
    System.out.println("Grade for math subject");
    for (Student student : students) {
        System.out.print("Student:" + " " + RandomNames.randomIdentifier() + " " + 
"Enter grade: ");
        double grade = myInput.nextDouble();
        studentGrades.add(new Grade(grade, student));
    }
}
}

Grade class used for the Subject classes.用于科目类的 class 等级。

public class Grade {
//has a grade, and a student object
private double grade;
public Student student;

public double getGrade() {
    return grade;
}

public Grade(double grade, Student student) {
    this.grade = grade;
    this.student = student;
}
}

Student class:学生 class:

public class Student {

}

Your application.你的申请。 You run this file.你运行这个文件。

public class App {
public static void main(String[] args) throws Exception {
 
    //School
    List<Student> studentList = new ArrayList<>();
    studentList.add(new Student());
    studentList.add(new Student());
    studentList.add(new Student());


    SchoolSubjects mathSubject = new MathSubject();
    SchoolSubjects englishSubject = new EnglishSubject();

    mathSubject.gradeStudents(studentList);
    englishSubject.gradeStudents(studentList);

    System.out.println("Average grade math:" + " " + mathSubject.getAverageValue());
    System.out.println("Average grade english:" + " " + 
englishSubject.getAverageValue());
}
}

Class to generate random names: Class 生成随机名称:

import java.util.HashSet;
import java.util.Set;

public class RandomNames {
// class variable
final static String lexicon = "ABCDEFGHIJKLMNOPQRSTUVWXYZ12345674890";

//final java.util.Random rand = new java.util.Random();

// consider using a Map<String,Boolean> to say whether the identifier is being used 
or not
final static Set<String> identifiers = new HashSet<String>();

public static String randomIdentifier() {
    StringBuilder builder = new StringBuilder();
    while (builder.toString().length() == 0) {
        int length = new java.util.Random().nextInt(5) + 5;
        for (int i = 0; i < length; i++) {
            builder.append(lexicon.charAt(new 
java.util.Random().nextInt(lexicon.length())));
        }
        if (identifiers.contains(builder.toString())) {
            builder = new StringBuilder();
        }
    }
    return builder.toString();
}
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM