Replacing an item in an Object array with null (java) - java

I'm starting to learn object orientation in my course and we have an object class called students. An object of the studentsclass stores the instance variables: studentName, studentNumber, and studentGPA. I have a boolean method in my object class that determines whether the student is a failing student or not (the student is failing if their GPA is > 2.0) and then I have a method in my worker class that is supposed to accept the array of students objects, and then if the student is failing, it replaces that object with "null".
My problem is that I'm having a hard time replacing the students objects with null, since java keeps throwing me or some such. Here's what I've tried:
public static void removeFailingStudents(Student[] students)
{
int count;
for (count=0; count<students.length; count++)
{
if(students[count].isFailing())
{
students[count] = null;
}
}
}
and
public static void removeFailingStudents(Student[] students)
{
int count;
for (count=0; count<students.length; count++)
{
if(students[count].isFailing())
{
students[count] = "null";
}
}
}
but when I compile/run these attempts it either throws me an exception or it yells at me because it is not of the type Student. How do I set an item in an array of objects to null?? Thanks for the help!
Here's my full code:
public class L2Q1
{
public static void main(String[] parms)
{
process();
System.out.println("\nEnd of processing.");
}
public static void process()
{
Student[] students;
Student[] newStudents;
students = getStudents();
printStudents(students);
printAverageGPA(students);
printHonourStudents(students);
removeFailingStudents(students);
printStudents(students);
newStudents = compactStudents(students);
printStudents(students);
printStudents(newStudents);
}
public static void printStudents(Student[] students)
{
int count;
System.out.println("Students:");
for (count=0; count<students.length; count++)
{
System.out.println(students[count].toString());
}
System.out.println();
}
public static void printAverageGPA(Student[] students)
{
double sumGPA;
int count;
sumGPA = 0;
for (count=0; count<students.length; count++)
{
sumGPA += students[count].getGPA();
}
double average = sumGPA / count;
System.out.println("The average GPA is " + average);
System.out.println();
}
public static void printHonourStudents(Student[] students)
{
int count;
System.out.println("Honour students:");
for (count=0; count<students.length; count++)
{
if(students[count].isHonourStudent())
{
System.out.println(students[count].toString());
}
}
System.out.println();
}
public static void removeFailingStudents(Student[] students)
{
int count;
for (count=0; count<students.length; count++)
{
if(students[count].isFailing())
{
students[count] = null;
}
}
}
public static Student[] compactStudents(Student[] students)
{
Student[] newStudents;
int count1;
int count2;
System.out.println("Compacting failing students.");
System.out.println();
count1 = 0;
for (count2=0; count2<students.length; count2++)
{
}
newStudents = new Student[0];
return newStudents;
}
public static Student[] getStudents()
{
Student[] students = new Student[]
{
new Student(7654321, "Lara Zhivago", 3.75),
new Student(7654322, "Betty Brown", 1.9),
new Student(7654323, "Chris Cross", 0.5),
new Student(7654324, "Dr. Dre", 4.0),
new Student(7654325, "Joe Cool", 2.0)
};
return students;
}
}
/******************************************************************/
/******************************************************************/
class Student
{
private int number;
private String name;
private double gpa;
public Student(int snum, String sname, double sgpa)
{
this.number = snum;
this.name = sname;
this.gpa = sgpa;
}
public double getGPA()
{
return gpa;
}
public boolean isHonourStudent()
{
boolean isHonourStudent = false;
if(getGPA() >= 3.5)
{
isHonourStudent = true;
}
return isHonourStudent;
}
public boolean isFailing()
{
boolean isFailing = false;
if(getGPA() < 2.0)
{
isFailing = true;
}
return isFailing;
}
public String toString()
{
return number + " " + name + " " + gpa;
}
}
Here's the exception message:
java.lang.NullPointerException
at L2Q1.printStudents(L2Q1.java:41)
at L2Q1.process(L2Q1.java:28)
at L2Q1.main(L2Q1.java:13)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at edu.rice.cs.drjava.model.compiler.JavacCompiler.runCommand(JavacCompiler.java:272)

The Problem
You are making elements in your students array null. Then you try to use toString() but on a null element. This is how it looks like: null.toString(), obviously that is bad.
Solution Without ArrayList
On the comments people suggested an ArrayList. I am assuming this is homework and you are forced to use an array, therefore you should do this:
Keep track of the size of the array. Use that to determine how many real elements, non-null elements, you have on the list. Like this:
for(int i = 0; i < arraySize; i++)
{
// Do something with the array here.
}
Make sure you declare arraySize as an instance variable.
private int arraySize = 0;
Remember you will need to increment arraySize for every new element and decrement it every time you null out an element.
Keep in mind that by the time your program finishes your array will have a trail of nulls at the end.
Hackish Solution
In the mean time you can do this to your printStudents() -- this is hackish and only a temporary fix.
public static void printStudents(Student[] students)
{
// Check if the array is null, good practice.
if(students == null)
return;
System.out.println("Students:");
for (int i = 0; i < students.length; i++)
{
// My hack: Check if element is null, if it is then skip it.
if(students[i] == null)
continue;
System.out.println(students[i].toString());
}
System.out.println();
}

This happens because you've already removed some of the students, turning them from Student to null. You're trying to call toString() on one of the non-existing students that are null.
I suggest you replace the array with ArrayList, from which you can actually remove elements. Alternatively, you can rebuild the array when you remove a student.

You are setting a Student object at an index to null, then later in a different method attempting to call toString() on a null object. Using List would help you work with this problem much more elegantly.
Without rewriting the whole code, here is how you could implement List instead:
public static void process() {
List<Student> students = new ArrayList<Student>();
List<Student> newStudents = new ArrayList<Student>();
...
Then when you loop through a List in all your different functions, you would use
for (int count = 0; count < students.size(); count++) {
//do stuff here
}
If you want to remove a student from a list, use
students.remove(count);
To populate the list, use
Student student1 = new Student(7654321, "Lara Zhivago", 3.75);
students.add(student1);
....

Related

How to fill Object Array and find minimum value for the Object Array

EDIT SOLUTION
Based on forpas code, I move thing around little bit, and now the minimum value displays as expected. Thank you guys for all your help.
public static StudentGrade findMinIndex(StudentGrade[] studentGrades)
{
StudentGrade studentGradeMin = studentGrades[0];
for(int i=0; i < studentGrades.length; i++)
{
if(studentGradeMin.getGrade()[0] > studentGrades[i].getGrade()[i])
{
studentGradeMin.getGrade()[0] = studentGrades[i].getGrade()[i];
}
}
System.out.println(studentGradeMin.getGrade()[0]);
return studentGradeMin;
}
EDIT:
Now that I can print out the number, I have problem with finding minimum value. I keep getting error message:
"The operator > is undefined for the argument type(s) StudentGrade, StudentGrade"
I need to find minimum value for my object array, but I can't print the object correctly. The result will not display like integers.
Can someone help me please?
This is my text file
6
John 97.5
Jim 99
Kathy 34
Steve 86.5
Stacy 43
Faith 88
This is my methods
//This is the constructor class
public class StudentGrade
{
private String[] names;
private double[] grades; // instance variable
// constructor initializes grades with parameter grades
public StudentGrade(double[] grades, String[] names)
{
this.grades = grades;
this.names = names;
}
// method to set the grades
public void setGrade(double[] grades)
{
this.grades = grades;
}
// method to retrieve the grades
public double[] getGrade()
{
return grades;
}
//Set name
public void setName(String[] names)
{
this.names = names;
}
// method to retrieve the names
public String[] getName()
{
return names;
}
}
//This is my main class
public static StudentGrade[] initialize(String inputFileName) throws FileNotFoundException
{
Scanner scan = new Scanner(new FileInputStream("grade.txt"));
int size = scan.nextInt();
String[] names = new String[size];
double[] grades = new double[size];
int index = 0;
String[] col = null;
while(scan.hasNextLine())
{
names[index] = scan.next();
grades[index] = scan.nextDouble();
index++;
}
StudentGrade[] studentGrades = new StudentGrade[grades.lenght];
for(int i=0; i< studentGrades; i++)
{
studentGrades[i] = new StudentGrade(grades, names);
}
for(int i=0; i< grades.length; i++)
{
System.out.println(studentGrades[i].getGrade());
}
scan.close();
return studentGrades;
}
//This is to find minimum value
public static StudentGrade findMinIndex(StudentGrade[] studentGrades)
{
StudentGrade studentGradeMax = studentGrades[0];
for(int i=1;i<studentGrades.length;i++)
{
if(studentGrades[i] > studentGradeMax) ==> Error "The operator > is undefined for the argument type(s) StudentGrade, StudentGrade"
{
studentGradeMax = studentGrades[i];
}
}
return studentGradeMax;
}
The code return these values instead of real number
[D#3d4eac69
[D#3d4eac69
[D#3d4eac69
[D#3d4eac69
[D#3d4eac69
[D#3d4eac69
You are printing by:
System.out.println(studentGrades[i].getGrade());
but getGrade() returns an array, so change to this:
System.out.println(Arrays.toString(studentGrades[i].getGrade()));
or if the array contains only 1 number:
System.out.println(studentGrades[i].getGrade()[0]);
Edit
public static StudentGrade findMinGrade(StudentGrade[] studentGrades) {
StudentGrade studentGradeMin = studentGrades[0];
for(int i=1; i < studentGrades.length; i++) {
if(studentGrades[i].getGrade()[0] < studentGradeMin.getGrade()[0]) {
studentGradeMin = studentGrades[i];
}
}
return studentGradeMin;
}
Check it, I hope there are no typos.
This returns the StudentGrade object inside the array studentGrades with the min grade.
The simplest way is to override the String toString() method from the Object class since that is the default method used when printing an object
So in your StudentGrade method you would add
#Override
public String toString() {
return //your fields
}
The problem here is that your member fields in StudentGrade are arrays which is a little strange so I guess your toString would look like this for example
#Override
public String toString() {
StringBuilder out = new StringBuilder();
for (String name : names) {
out.append(name);
out.append(", ");
}
for (int i = 0; i < grades.length - 1; i++) {
out.append(grades[i]);
out.append(", ");
}
out.append(grades[grades.length - 1]);
return out.toString();
}

Passing Multiple Generics Into Java Method

Using Java. The goal is to search for a value, given as a generic, in an ArrayList, also given as a generic.
My Student class (pertinent parts)
public class Student<T> implements Comparable
{
private String studName;
private Integer gradeAverage;
public Student(String nameIn, int gradeIn)
{
studName = nameIn;
gradeAverage = gradeIn;
}
public int compareTo(Object obj)
{
Student s1 = (Student)obj;
return(this.gradeAverage - s1.gradeAverage);
}
}
My Search; thinking there may be a problem with the generic specifications
public class SearchMethods<T,S>
{
public <T extends Comparable, S extends Comparable> void BinarySearch(T[] inputArray, S searchValue)
{
boolean found = false;
for(int i = 0; i < inputArray.length; i++)
{
T search = inputArray[i];
if(searchValue.compareTo(search) == 0)
{
System.out.println(searchValue + " is at index " + i);
found = true;
}
}
if(found == false)
{
System.out.println(searchValue + " was not found");
}
}
}
And my main()
public static void main(String[] args)
{
Student studentOne = new Student("James",92);
Student studentTwo = new Student("Mary",95);
Student studentThree = new Student("Bobbie",82);
Student studentFour = new Student("Emily",100);
Student studentFive = new Student("Joey",88);
ArrayList<Student> studentList = new ArrayList<Student>();
studentList.add(studentOne);
studentList.add(studentTwo);
studentList.add(studentThree);
studentList.add(studentFour);
studentList.add(studentFive);
SearchMethods<ArrayList, Student> searchMethods = new SearchMethods<ArrayList, Student>();
searchMethods.BinarySearch(studentList, studentOne); //Should print that it was found at index 0
The given compiler error states that an argument mismatch, that ArrayList cannot be converted to T#1[]. But that's the whole point of generics, right?? Interestingly, no analogous error is given for the second type, but maybe the compiler just hasn't read ahead that far.
I'm pretty sure my syntax is OK at the class level, so the error is likely with the calling objects in main(). Though, I could be wrong.
Thanks in advance!
You need to convert arraylist to an array. Check the argument for Binary Search.
Try this:
SearchMethods<ArrayList, Student> searchMethods = new SearchMethods<ArrayList, Student>();
searchMethods.BinarySearch(studentList.toArray(new Student[studentList.size()]), studentOne);
You could also change BinarySearch where you work with an arraylist.
While this is not part of the question, it is important not compute the difference for compareTo or you will get overflow error.
Try this:
class Student<T> implements Comparable
{
private String studName;
private Integer gradeAverage;
public Student(String nameIn, int gradeIn)
{
studName = nameIn;
gradeAverage = gradeIn;
}
public int compareTo(Object obj)
{
Student s1 = (Student)obj;
if (this.gradeAverage < s1.gradeAverage){
return -1;
}
if(this.gradeAverage == s1.gradeAverage){
return 0;
}
return 1;
}
#Override
public String toString(){
return "student name="+studName +" grade average= " + gradeAverage;
}
}

Wrong object is being deleted from array

My program is not having any errors, but the wrong student is being deleted from my course (an array) and I'm not sure why. If I change the name to the 3rd student (James), I get an NPE error on the dropStudent lines. I think it might have something to do with my dropStudent method, but I think it should loop through course with index equal to 'i' and when that index equals the name, it becomes null leaving the other 2 students.
I'll post the code below along with my output.
package reviseCourse;
import java.util.*;
public class ReviseCourse {
public static void main(String[] args) {
// TODO Auto-generated method stub
// Create new course to enroll students in
ReviseCourse cs216 = new ReviseCourse("cs216");
// Add 3 students to the course
cs216.addStudent("William");
cs216.addStudent("Angela");
cs216.addStudent("James");
// Drop the student William from the course
cs216.dropStudent("William");
// Print course name and students individually by looping through the numberOfStudents
System.out.println("The students in the course " + cs216.getCourseName() + " are:");
for (int i = 0; i < cs216.getNumberOfStudents(); i++) {
System.out.print(students[i] + " ");
}
}
private String courseName;
private static String[] students = new String[100];
private String[] course = new String[students.length + 1];
private int numberOfStudents;
public void populateCourse() {
for (int i = 0; i < students.length; i++) {
course[i] = students[i];
System.out.println(course[i]);
}
}
public ReviseCourse(String courseName) {
this.courseName = courseName;
}
public void addStudent(String student) {
for (int i = 0; i < students.length; i++) {
course[i] = students[i];
}
students[numberOfStudents] = student;
numberOfStudents++;
}
public String[] getStudents() {
return students;
}
public int getNumberOfStudents() {
return numberOfStudents;
}
public String getCourseName() {
return courseName;
}
public void dropStudent(String student) {
for (int i = 0; i < course.length; i++) {
if (course[i].equals("William")) {
course[i] = null;
numberOfStudents--;
break;
}
}
}
// Deletes all students from the course
public void clear() {
numberOfStudents = 0;
}
}
Output:
The students in the course cs216 are:
William Angela
dropStudent modifies the course array, but not the student array, which you're printing from. The bigger issue is that you're just assigning null to the student you want to delete, but decrementing the number of students, so even if you print from courses you won't get the right output.
If the array of students is:
William | Angela | James : numStudents = 3
Then dropping William makes the array:
null | Angela | James : numStudents = 2
Now if you try to print the students, your code will will print the first two elements, which are null and Angela. Probably not what you want.
You should either be shifting over elements when you drop students, so that the array would instead look like:
Angela | James | null : numStudents = 2
After dropping William, or instead of reinventing the wheel just use ArrayList.
In your dropStudent method:
if (course[i].equals("William")) {
So this method is only ever going to drop William, no matter which student is actually passed into it.
Additionally, you are looping through the students array, but dropStudent only removes students from the course array.
public void dropStudent(String student) {
for (int i = 0; i < course.length; i++) {
if (course[i].equals(student) {
course[i] = null;
numberOfStudents--;
//can re order to keep the array tidy, ie go with for if you find a
//null then set it to be the next value in the array; thus will keep
//array management more efficient
break;
}
}
}

Values not printed out when using Comparator to sort ArrayList

I'm working on a program where I'm inputting values(String and int) into arrays, putting those values into an objects which go into an array list to be sorted by the the int value. When I run the program though, it prints out:
Sorted List Entries:
Item Name:null---Quant:0
Item Name:null---Quant:0
Item Name:null---Quant:0 //etc..
I'm trying to learn on my own here but I'm not sure what to do.
My main class:
import java.io.*;
import java.util.*;
public class InputItem
{
public static void main(String args[])
{
String again;
String names[] = new String[100];
int quant[] = new int[100];
int row=0;
do{
System.out.println("Please input assignment name:");
Scanner newName = new Scanner(System.in);
String name = newNamet.next();
names[row] =name;
System.out.println("Please input assignment quant:");
Scanner quantI = new Scanner(System.in);
int quantity = quantI.nextInt();
quant[row] = quantity;
System.out.println("Would you like to add another item? Enter 'Yes' or 'No'");
Scanner input = new Scanner(System.in);
again = input.next();
row++;
}
while(again.equalsIgnoreCase("Yes"));
List<Items> work = new ArrayList<Items>();
for(int count = 0; count<row; count++)
{
work.add(new Items((names[row]),(quant[row])));
}
Collections.sort(work, new MyComp());
System.out.println("Sorted List Entries: ");
for(Items e:work)
{
System.out.println(e);
}
}
}
Class with Comparator:
import java.util.*;
class MyComp implements Comparator<Items>
{
#Override
public int compare(Items e1, Items e2)
{
if((e1).getQuant()< (e2).getQuant())
{
return 1;
}
else
{
return -1;
}
}
}
public class Items
{
private String name;
private int quant;
public Items(String n, int q)
{
this.name = n;
this.quant = q;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getQuant()
{
return quant;
}
public void setQuant(int quant)
{
this.quant = quant;
}
public String toString()
{
return "Item Name:" + this.name+"---Quant:" +this.quant;
}
}
The problem is here...
for (int count = 0; count < row; count++) {
work.add(new Items((names[row]), (quant[row])));
}
You're using row, which was defined in the previous section of code to keep track of which element you were updating, but is now pointing to the next element in the array (or an empty element). This basically means you are constantly adding the same (empty) values to your Items
Instead, you should be using count
for (int count = 0; count < row; count++) {
work.add(new Items((names[count]), (quant[count])));
}

How do I find the name of the top student in an array list?

I am studying Java and have been asked to produce methods that can be used in order to gather statistics based off of the student names and marks that are entered. I have worked out how to calculate the top mark but what I need to do is return the name of the student that got the highest mark, how would I do this? I was thinking I could try to return the string before the highest int but I wasn't sure how I would do that.
Edit: Just to make it clear, currently, when END is entered in to the console following the input of data, the top mark is returned - I need to return the mark of the best student.
import java.util.*;
public class Course {
private ArrayList<Student> people = new ArrayList<Student>();
private int passing = 0;
private int failing = 0;
private int top = Integer.MIN_VALUE;
private int sum = 0;
public void add( Student student ) {
people.add( student );
if(student.getMark() >= 40){
passing++;
}
else {
failing++;
}
sum += student.getMark();
if(student.getMark() > top) {
top = student.getMark();
}
}
public int pass() {
return passing;
}
public int fail() {
return failing;
}
public int top() {
return top;
}
public double average() {
return sum / people.size();
}
}
Thanks for any help.
Update: BinaryJudy, I did what you said but I get a 'NoSuchMethod' error for the top name, this is what I changed my code to:
import java.util.*;
public class Course {
private ArrayList<Student> people = new ArrayList<Student>();
private int passing = 0;
private int failing = 0;
private int top = Integer.MIN_VALUE;
private int sum = 0;
private String topName;
public void add( Student student ) {
people.add( student );
if(student.getMark() >= 40){
passing++;
}
else {
failing++;
}
sum += student.getMark();
if(student.getMark() > top) {
top = student.getMark();
}
if(student.getMark() > top) {
top = student.getMark();
topName = student.getName();
}
}
public int pass() {
return passing;
}
public int fail() {
return failing;
}
public String top() {
return topName;
}
public double average() {
return sum / people.size();
}
}
Any idea why? :)
You have already found the student with the top mark. Update the top name with the name of the student when the top mark is found. Finding the top mark results in also finding the name.
String topName;
if(student.getMark() > top) {
top = student.getMark();
topName = student.getName();
}
Note that you're storing a bunch of students who I assume each have a mark for the course. All you need to do is cycle through that Arraylist, and find out who has the highest mark, and return that student.
Something like this may work for you:
public String topStu(ArrayList<Student> list) { // take in any list of students
int topStudentScore = 0; // default value
Student topStudent = null;
for (student x : list) { // cycle through all students in the list
if (x.getMark() > topStudentScore) { // if the score is higher than the current listed score
topStudentScore = x.getMark(); // update the top score
topStudent = x; // update top student
}
}
return topStudent.getName(); // return his name
}
You can easily write this to be a function for a specific course - you can remove the parameter, and directly access the private ArrayList if you want to.
Alternatively, you can write the above function to be a static function that takes any list of students from any course.
If a student is unique in the people list and insert order has no importance, then you can change
ArrayList<Student> people = ...;
By
// Java7 and before
SortedSet<Student> people = new TreeSet<>(new Comparator<Student>() {
public int compare(Student s1, Student s2) {
return s2.getMark()-s1.getMark(); // sorted by decreasing mark
}
});
// Java8
SortedSet<Student> people
= new TreeSet<>(Comparator.comparingInt(Student::getMark).reversed());
Then finding the top student is matter of getting the first from the people set:
Student top = people.first();
As a bonus, you can compute easily the ranking for all student. Adding new student will put them at the right ranking.
Note: Be aware that modifying a student mark after insertion will not change automatically its ranking and should be handled through a sequence of :
Student s = ...;
people.remove(s);
s.setMark(42);
people.add(s);
public class Classroom
{
Student[] students;
int numStudentsAdded;
public Classroom(int numStudents)
{
students = new Student[numStudents];
numStudentsAdded = 0;
}
public Student getTopStudent()
{
int y = 0;
//have to use numStudentsAdded
for ( int i = 0 ; i < numStudentsAdded ; i++)
{
if (students[y].getAverageScore() < students[i].getAverageScore())
{
y = i;
}
}
return students[y] ;
}
public void addStudent(Student s)
{
students[numStudentsAdded] = s;
numStudentsAdded++;
}
public void printStudents()
{
for(int i = 0; i < numStudentsAdded; i++)
{
System.out.println(students[i]);
}
}
}

Categories

Resources