moo cow
moo cow

Reputation: 181

Comparing lines for a similar String in a text file

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.

Upvotes: 2

Views: 140

Answers (3)

0xCursor
0xCursor

Reputation: 2268

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.

Upvotes: 1

Peter1982
Peter1982

Reputation: 518

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

Upvotes: 0

AlexS
AlexS

Reputation: 5345

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.

Upvotes: 2

Related Questions