2

I have a text file which looks something like this:

6
3.3 John Rodgers
3.9 Jim Braash
3.5 Kathy Calderon
3.2 Steve Hernandez
2.4 Stacy Lu
2.8 Faith Simmons

I've already written a Student class, which has basic functions:

package com.company;

public class Student {

    private String firstName;
    private String lastName;
    private double grades;

    public Student(String firstName, String lastName, double grades) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.grades = grades;
    }

    @Override
    public String toString() {
        return lastName + ", " + firstName + ", " + grades;
    }

    @Override
    public boolean equals(Object obj) {

        if(obj == null){
            return false;
        }

        Student other = (Student) obj;

        if (other.firstName.equals(this.firstName) && other.lastName.equals(this.lastName) && other.grades == this.grades) {
            return true;
        } else {
            return false;
        }
    }

    public String getFirstName() {

        return this.firstName;
    }

    public String getLastName() {

        return this.lastName;
    }

    public double getGrade() {

        return this.grades;
    }

    public void setFirstName(String firstName) {

        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public void setGrades(double grades) {
        this.grades = grades;
    }

}

And this is my Main class:

package com.company;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.Scanner;


public class Main {

    public static void main(String[] args) throws FileNotFoundException {
        Student[] s = initialize();
        Student max = maxIndex(s);
        Student min = minIndex(s);
        double avg = avg(s);
        flush(max, min, avg);

    }

    public static void flush(Student max, Student min, double avg) throws FileNotFoundException {
        DecimalFormat df = new DecimalFormat("#.#");
        double avgFormatted = Double.parseDouble(df.format(avg));
        PrintWriter writer = new PrintWriter("final.txt");
        writer.write("Highest: " + max);
        writer.write("\n");
        writer.write("Lowest: " + min);
        writer.write("\n");
        writer.write("Average GPA: " + avgFormatted);
        writer.close();
    }

    public static Student[] initialize() throws FileNotFoundException {
        Scanner reader = new Scanner(new File("data.txt"));
        int size = reader.nextInt();
        Student[] students = new Student[size];
        int index = 0;

        while (reader.hasNextLine()) {
            double grades = reader.nextDouble();
            String firstName = reader.next();
            String lastName = reader.next();
            Student student = new Student(firstName, lastName, grades);
            students[index] = student;
            index++;
        }
        return students;
    }

    public static double avg(Student[] students) {
        double avg = 0;
        double sum = 0;
        for (int i = 0; i < students.length; i++) {
            sum += students[i].getGrade();
            avg = sum / students.length;
        }
        return avg;
    }

    public static Student maxIndex(Student[] students) {
        int max = 0;
        for (int i = 1; i < students.length; i++) {
            if (students[i].getGrade() > students[max].getGrade()) {
                max = i;
            }
        }

        return students[max];
    }

    public static Student minIndex(Student[] students) {
        int min = 0;
        for (int i = 1; i < students.length; i++) {
            if (students[i].getGrade() < students[min].getGrade()) {
                min = i;
            }
        }
        return students[min];
    }
}

So, my question involves dealing with the file. Let's say I added the name Jim Braash again into my file without changing the integer at the top. So my file looks like this:

6
3.3 John Rodgers
3.9 Jim Braash
3.9 Jim Braash
3.5 Kathy Calderon
3.2 Steve Hernandez
2.4 Stacy Lu
2.8 Faith Simmons

Even though there are 7 lines, there are still only 6 students because one is repeated. I already implemented the equals() method in my Student class, but I am unable to figure out how I would skip the line in the main() method and still have the same results as before. Thanks.

0xCursor
  • 2,242
  • 4
  • 15
  • 33
moo cow
  • 181
  • 13
  • 2
    The only thing I can think about is you should do a preprocessing to your file, deleting all duplicate lines before you do the actual processing. Add a method that you call first to delete all duplicate lines. See this for an example: https://stackoverflow.com/questions/996041/deleting-duplicate-lines-in-a-file-using-java – ISlimani Jul 01 '18 at 21:25
  • You should probably close your `Scanner` when you are done using it - `reader.close()`. – 0xCursor Jul 01 '18 at 22:11

3 Answers3

2

Use HashSet<Student> instead of Student[] and override hascode to conform to your equals. You won't have any duplicates any more.

Be aware that you can cause serious problems with wrong implementations of equals and hashcode. Properties that are used in this methods shouldn't be modified. This would cause possible duplicates and/or that you may not be able to accesss or remove the modified element in a HashSet.

AlexS
  • 5,295
  • 3
  • 38
  • 54
1

The other answers have good ideas. But, if you just want a simple way to do it using your equals() method from your Student class, you could try the following for your initialize() method:

public static Student[] initialize() throws FileNotFoundException {
    Scanner reader = new Scanner(new File("data.txt"));
    int size = reader.nextInt();
    Student[] students = new Student[size];
    int index = 0;

    while (reader.hasNextLine()) {
        double grades = reader.nextDouble();
        String firstName = reader.next();
        String lastName = reader.next();

        Student student = new Student(firstName, lastName, grades);

        boolean duplicate = false;
        for (int i = 0; i < students.length; i++) {
            if (student.equals(students[i])) {
                duplicate = true;
                break;
            }
        }

        if (!duplicate) {
            students[index] = student;
            index++;
        }
    }

    reader.close(); // <--- Make sure to close the Scanner
    return students;
}

Let me know if this works for you.

0xCursor
  • 2,242
  • 4
  • 15
  • 33
  • Thank you so much man. I could have never figured this logic. I realize that this is a O(n^2) and I'm wondering if there is a way to have a faster runtime. However, this alone answers my question! – moo cow Jul 02 '18 at 20:34
  • By the way, I took out the prevStudents array and just used students array and that worked as well – moo cow Jul 02 '18 at 20:36
  • 1
    @moo cow Awesome, glad I could help you out. And yeah, just comparing `student` to the array of `students` is a nice simplification. I will add that simplification to my post. – 0xCursor Jul 02 '18 at 21:48
0

Instead of array of Student, try use Set of student

A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element.

This data type have only unique item.

EDIT 1 With array

     while (reader.hasNextLine()) {
        Double grades = Double.valueOf(reader.next());
        String firstName = reader.next();
        String lastName = reader.next();
        Student student = new Student(firstName, lastName, grades);
        if (Arrays.stream(students).noneMatch(s -> student.equals(s))) {
            System.out.println(student);
            students[index] = student;
            index++;
        }
    }

EDIT 2

You can replace max, min, avg calculation with streams

 public static void main(String[] args) throws FileNotFoundException {
    Student[] s = initialize();
    Student max = Arrays.stream(s).max(Comparator.comparing(student -> student.getGrade())).orElse(null);
    Student min = Arrays.stream(s).min(Comparator.comparing(student -> student.getGrade())).orElse(null);
    double avg = Arrays.stream(s).map(student -> student.getGrade()).reduce(0d, (x,y) -> x + y).doubleValue() / s.length;
    flush(max, min, avg);
}
Peter1982
  • 518
  • 2
  • 11