1

I'm trying to write a program to read a file called scores.txt where it prints out the ID of the student with the highest average across their courses along with their student ID.

This is what scores.txt looks like:

34     c081 c082 c083 c084
S2023  99   75   85   62
S2025  -1   92   67   52
S1909  100  83   45   -1

So basically, the 34 a the beginning is a 3 for the number of students and a 4 for the number of courses (yes, I know this is silly, but the file was provided for my task). The c numbers such as c081 are course codes at the school, and the s numbers such as s2023 are student numbers. The figures in the middle represent their scores, the -1 also means they weren't enrolled in the unit.

Anyway, so far I've written a MySchool class and a Student class, which I'll paste below:

import java.io.File;
import java.io.FileNotFoundException; 
import java.util.ArrayList;
import java.util.Scanner; 

public class MySchool {
    public static void main(String[] args) {
        int numberOfStudents;
        ArrayList<Student> allStudents = new ArrayList<Student>() ;

        // grab first line only, and check if first target is integer, or string
        try {

            File scoresFile = new File("Scores.txt");
            Scanner scoresFileReader = new Scanner(scoresFile);

            String headerRow = scoresFileReader.nextLine();
            numberOfStudents = headerRow.charAt(0);

            while(scoresFileReader.hasNextLine()) {
            for (int studentI = 0; studentI < numberOfStudents; studentI++) {
                String studentText = scoresFileReader.nextLine();
                System.out.println(studentText);
                Student student = new Student(studentText);
                allStudents.add(student);
            }}

            scoresFileReader.close();

        } catch (FileNotFoundException e) {
            System.out.println("An error occurred");
            e.printStackTrace();
        }

        float highestAverage = 0;
        String highestScoringStudentNumber = null;

        for (Student student : allStudents) {
            if (student.getAverageScore() > highestAverage) {
                highestAverage = student.getAverageScore();
                highestScoringStudentNumber = student.getStudentNumber();
            }

        }
        System.out.println("Highest scoring student: " + highestScoringStudentNumber);
    }
}
import java.util.ArrayList;

public class Student {

    private String studentNumber;
    private ArrayList<Integer> scores = new ArrayList<Integer>();

    public Student(String studentText) {
        String[] parts = studentText.split(studentText, ' ');
        this.studentNumber = parts[0];

        for (int i = 1; i < parts.length - 1; i++) {
            scores.add(Integer.parseInt(parts[i + 1]));
        }
    }

    public String getStudentNumber() {
        return this.studentNumber;
    }

    public float getAverageScore() {
        int sum = 0;
        for (int i = 0; i <this.scores.size(); i++) {
            sum += this.scores.get(i);
        }
        return sum / this.scores.size();
    }


}

Basically I want to be able to have an object for students where they have their student number and their scores. This is so that I can give them an average.

However, it seems that I've done something wrong in reading the file in (Haven't ever done this before), because the String studentText = scoresFileReader.nextLine(); line throws me an error that states : Exception in thread "main" java.util.NoSuchElementException: No line found at java.base/java.util.Scanner.nextLine(Scanner.java:1651) at MySchool.main(MySchool.java:22)

If it's any help, the three student codes and their scores print out the way they should before I get this error.

Can anyone help me to get this up and running? I'm not sure how to resolve it

EDIT:

I've actually noticed the issue to be that somehow numberOfStudents is being set to 51 when there's no 51 in the data. Even if I run the code below, it prints the first value of headerRow confirming that it is 3, which is correct. The when I use the same code to assign it to numberOfStudents suddenly it's become 51 when it prints again?

import java.io.File; // Import the File class
import java.io.FileNotFoundException; // Import this class to handle errors
import java.util.ArrayList;
import java.util.Scanner; // Import the Scanner class to read text files

public class MySchool {
    public static void main(String[] args) {
        int numberOfStudents;
        ArrayList<Student> allStudents = new ArrayList<Student>() ;

        // grab first line only, and check if first target is integer, or string
        try {

            File scoresFile = new File("Scores.txt");
            Scanner scoresFileReader = new Scanner(scoresFile);


            String headerRow = scoresFileReader.nextLine();

            System.out.println(headerRow.charAt(0));

            numberOfStudents = headerRow.charAt(0);

            System.out.println(numberOfStudents);


            for (int studentI = 0; studentI < numberOfStudents; studentI++) {
                String studentText = scoresFileReader.nextLine();
                System.out.println(studentText);
                Student student = new Student(studentText);
                allStudents.add(student);
            }

            scoresFileReader.close();

        } catch (FileNotFoundException e) {
            System.out.println("An error occurred");
            e.printStackTrace();
        }

        float highestAverage = 0;
        String highestScoringStudentNumber = null;

        for (Student student : allStudents) {
            if (student.getAverageScore() > highestAverage) {
                highestAverage = student.getAverageScore();
                highestScoringStudentNumber = student.getStudentNumber();
            }

        }
        System.out.println("Highest scoring student: " + highestScoringStudentNumber);
    }
}
Jaimee-lee Lincoln
  • 365
  • 1
  • 3
  • 11
  • 1
    A short debugging session would reveal where the issue is. A for-loop inside of while-loop doesn't seem right to me. It's one or the other. And you should check what is the actual value of `numberOfStudents` - if it is what you expect. – Amongalen Jun 15 '20 at 08:45
  • Good point actually! I've just had a look and it seems that the value of `numberOfStudents` is 51. I can't seem to work out where this value would have come from considering it isn't in the data at all, let alone the first character? Now I'm more stumped than I was before, any thoughts? – Jaimee-lee Lincoln Jun 15 '20 at 08:51
  • 1
    try applying some software design: break the problem down by having separate methods for reading thee header, reading a line of data, parsing a line of data. write unit tests for each method and test them separately. – Bohemian Jun 15 '20 at 09:03

1 Answers1

1

The problem comes from the fact that you're actually reading an ASCII code of the char, not the value itself - '3' == 51. You need to convert the character to the correct value. The simpliest way is to use Character.getNumericValue(), eg.:

char c = headerRow.charAt(0);
numberOfStudents = Character.getNumericValue(c);  
Amongalen
  • 3,101
  • 14
  • 20
  • Oh of course, that makes sense. I suppose in hindsight it was also strange that it was returning a value that more than a single character! Thank you! – Jaimee-lee Lincoln Jun 15 '20 at 09:10