0

I'm new to Java and I'm writting a program that manages students, their subjects and the grades in that subject.

The code asks for the details of the student and then it saves all to an 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:

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:

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.

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.

2
  • 3
    Maybe it would be better if every instance of Student could have a method that returns the sum of their grades and one of how many grades they have and simply / them and will give your desired output... And you are breaking Java Code Conventions class names should start with UpperCase , and name it Student not Students. Commented Mar 12, 2021 at 19:26
  • 1
    If you want to get the grades from a certain subject, you'll need to have a method that accepts the subject, and compare. Unrelated, but the students class should be named using standard Java naming conventions, and since it represents a single student, should be the singular Student. Commented Mar 12, 2021 at 19:26

3 Answers 3

1

The right way to architect this is first, you need to abstract Student as a 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).

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.

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.

Sign up to request clarification or add additional context in comments.

1 Comment

I had a class for Options, other for students and the Main, did it as you say and the called that method in the getaveragevalue and it worked, thanks!
1

Your way

Using your code, presumably each of your three grades by position represent three different courses. 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.

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. So we must cast our int to a float before doing the division.

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. Likely you would represent Student in a class, which in turn might contain a collection of objects of a 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. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString.

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. So if no class, then no students earned any grades. So rather than report a number we want to report an empty 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.

By the way, be aware that floating-point types such as float/Float trade away inaccuracy for speed of execution. If you care about accuracy, use BigDecimal class instead.

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.

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.

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….

Comments

-1

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.

We represent a subject with 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:

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:

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.

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:

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:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.