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;
}
}
}
Related
How could I remove an object inside a Linkedlist. I have a class account with studentId and studentName. I enter the objects inside the list, but when I try to remove I do not know how to do it. Because every time you remove an element from the middle of the list it gets organized, meaning the indexes change. So how can I get the studentId attribute and remove the object inside the linkedList.
Sample:
LinkedList: Account{studentId = 1, studentName = nome1} = index = 0 ,
LinkedList: Account{studentId = 2, studentName = nome2} = index = 1 ,
LinkedList: Account{studentId = 3, studentName = nome3} = index = 2.
what I would like was for the user to insert the studentId that he wants to delete and I can do a code that searches and deletes that object.
public Account{
private int studentID;
private String StudentName;
}
public static void main(String[] args){
int accountNumber;
LinkedList<Account> linkedAccount = new LinkedList<>();
Account obj1;
System.out.println("Type the acc number: ");
accountNumber = in.nextInt();
obj1 = linkedAccount.remove(accountNumber);
System.out.println("The " + obj1 + " has been deleted");
}
Every time I delete an object from the middle it changes the index of the linkedList. Rearranging. So i do not know how to do it can you help me?
If you don't need to keep a reference to the object you remove, you can just
linkedAccount.removeIf(acc -> acc.getStudentID() == accountNumber);
If you want to keep a reference to the element you remove you can
for (Account acc : linkedAccount) {
if (acc.getStudentID() == accountNumber) {
obj1 = acc;
linkedAccount.remove(acc);
break;
}
}
// OR
for (int i = 0; i < linkedAccount.size(); i++) {
if (linkedAccount.get(i).getStudentID() == accountNumber) {
obj1 = linkedAccount.remove(i);
break;
}
}
Notice that in most case and basiclly an ArrayList is sufficient When to use LinkedList over ArrayList in Java?
Currently, you're using accountNumber as the index which is incorrect, instead loop over the list and find the index of the object and then remove:
for (int i = 0; i < linkedAccount.size(); i++) {
if (linkedAccount.get(i).getStudentID() == accountNumber) {
obj1 = linkedAccount.remove(i);
break;
}
}
Further, why are you using a LinkedList instead of an ArrayList? the latter is almost always favourable.
I think the best option is to search the account in the list by the studentID and then remove it.
public Account{
private int studentID;
private String StudentName;
public int getStudentID() {
return this.studentID;
}
}
public static void main(String[] args){
int accountNumber;
LinkedList<Account> linkedAccount = new LinkedList<>();
Account obj1;
System.out.println("Type the acc number: ");
accountNumber = in.nextInt();
for (int i = 0; i < linkedAccount.size(); i++) {
if (accountNumber == linkedAccount.get(i).getStudentID()) {
System.out.println("The student " + linkedAccount.get(i).getStudentID() + " has been deleted");
linkedAccount.remove(i);
break; // This is to exit for loop, but if you want to delete every instance in the list with this ID you can skip this break
}
}
}
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]);
}
}
}
I am attempting to sort the values in my program using the Bubble Sort method. I believe that my code in the organisedRoom method is correct. However when I run the code, add some customers and then attempt to sort them, the program crashes. If anyone can please point me in the right direction I would greatly appreciate it.
package test;
import java.io.IOException;
import java.util.Scanner;
public class Test {
private class Customer implements Comparable<Customer>{
private String name;
public Customer(String name) {
this.name = name;
}
//Override to stop the program returning memory address as string
#Override
public String toString() {
return name;
}
#Override
public int compareTo(Customer c) {
return name.compareTo(c.name);
}
}
//Array to store customers
public Customer[] customers;
public Scanner input = new Scanner(System.in);
public Test(int nRooms) throws IOException {
customers = new Test.Customer[nRooms];
System.out.println("Welcome to the Summer Tropic Hotel\n");
chooseOption();
}
final JFileChooser fc = new JFileChooser();
// Call new Hotel with int value to allocate array spaces
public static void main(String[] args) throws IOException {
Test t = new Test(11);
}
// New procedure to return User input and point to next correct method
private String chooseOption() throws IOException {
// Set to null, this will take user input
String choice;
//Menu options
System.out.println("This is the Hotel Menu. Please choose from the following options:\n");
System.out.println("A: " + "This will add a new entry\n");
System.out.println("O: " + "View booked rooms, in order of customers name.\n");
System.out.println("X: " + "Exit the program\n");
// Take user input and assign it to choice
choice = input.next();
// Switch case used to return appropriate method
switch (choice.toUpperCase()) {
case "A" :
System.out.println("");
addCustomer();
return this.chooseOption();
case "O" :
System.out.println("");
organisedRoom();
return this.chooseOption();
case "X":
System.exit(0);
}
return choice;
}
// Add a new customer to the Array
public void addCustomer() throws IOException {
// New variable roomNum
int roomNum = 1;
// Loop
do {
// Take user input as room number matching to array index - 1
System.out.println("Please choose a room from 1 to 10");
roomNum = input.nextInt() - 1;
// If room is already booked print this
if (customers[roomNum] != null) {
System.out.println("Room " + roomNum + 1 + " is not free, choose a different one.\n");
this.addCustomer();
}
// Do until array index does not equal to null
} while (customers[roomNum]!= null);
System.out.println("");
// User input added to array as name replacing null (non case-sensetive)
System.out.println("Now enter a name");
customers[roomNum] = new Customer(input.next().toLowerCase());
// Customer (name) added to room (number)
System.out.println(String.format("Customer %s added to room %d\n", customers[roomNum], roomNum + 1));
}
private void organisedRoom() {
boolean flag = true;
Customer temp;
int j;
while (flag) {
flag = false;
for (j = 0; j < customers.length - 1; j++) {
if (customers[j].compareTo(customers[j+1]) < 0) {
temp = customers[j];
customers[j] = customers[j + 1];
customers[j + 1] = temp;
flag = true;
}
}
}
}
}
I think this is because the initialisation of the array adds null to all the array index places.
The stack trace is as follows:
Exception in thread "main" java.lang.NullPointerException
at test.Test$Customer.compareTo(Test.java:34)
at test.Test.organisedRoom(Test.java:133)
at test.Test.chooseOption(Test.java:83)
at test.Test.chooseOption(Test.java:79)
at test.Test.chooseOption(Test.java:79)
at test.Test.<init>(Test.java:46)
at test.Test.main(Test.java:55)
Java Result: 1
It fails because you create Customer[] which will be initialized with11 null references. If you want to order them all elements in the array will be compared. Which lead into the java.lang.NullPointerException.
Store the Customer in an ArrayList. Then you should be able to prevent this error.
edit
If you really need to stick as close as possible to your current code. The following would fix your sorting. (don't use this solution for a real life project)
private void organisedRoom() {
for (int i = customers.length - 1; i > 0; i--) {
for (int j = 0; j < i; j++) {
if (customers[j + 1] == null) {
continue;
}
if (customers[j] == null ||customers[j + 1].compareTo(customers[j]) < 0) {
Customer temp = customers[j + 1];
customers[j + 1] = customers[j];
customers[j] = temp;
}
}
}
System.out.println("show rooms: " + Arrays.toString(customers));
}
edit 2
To keep most of your current code, you might store the room in the Customer instance (which I personally would not prefer).
// change the constructor of Customer
public Customer(String name, int room) {
this.name = name;
this.room = room;
}
// change the toString() of Customer
public String toString() {
return String.format("customer: %s room: %d", name, room);
}
// store the Customer like
customers[roomNum] = new Customer(input.next().toLowerCase(), roomNum);
Your implementation of Bubble Sort is incorrect. It uses nested for loops.
for(int i = 0; i < customers.length; i++)
{
for(int j = 1; j < (customers.length - i); j++)
{
if (customers[j-1] > customers[j])
{
temp = customers[j-1];
customers[j-1] = customers[j];
customers[j] = temp;
}
}
}
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);
....
I am trying to go through a list of names with amounts.
One array has the name of the person , the other has the amount the person gave i.e. john, 55 sally 40 john 33 sarah 55.
My objective is to total the like names and print out the name of the person and the total amount that was given.
John gave twice so he should total 88. But I am getting the total right but my program is printing the name twice. So john 88 is printing twice... I know its likely because I put it in the first for loop its iterating the entire length of the array.
But I am unsure how to solve this?
import java.util.*;
public class chapterfive {
public static void main (String[]args) {
Scanner in = new Scanner (System.in);
String[]names = new String[4];
int[] scores = new int[4];
for (int i = 0; i<names.length; i++) {
names[i] = in.next();
scores[i] = in.nextInt();
}
int amount = 0;
String firstname = "";
for (int i = 0; i < names.length; i++) {
for (int j=0; j < names.length; j++) {
if (names[j].equals(names[i]))
amount += scores[j];
}
System.out.println(names[i] + " " + amount);
amount = 0;
}
}
}
You can see that they have a relationship like Name -> Score , so if you think more abstract this is a dictionary with Key (Name) and Value (Score) , so you can use another data-structure like a Map or you can use an array and make a class Person , have the arrayOrderer and when you add a new person check if that person exist in the array..
Example :
Map <String , Integer> people = new HashMap<>();
for (int i=0; i<lengthYouWant; i++)
{
String name=in.next();
int score=in.nextInt();
if(people.contains(name)){
score= people.get(name)+score;
}
people.put(name,score);
}
Should be using a Map to simplify things, rather than keeping track of two arrays. But heres a fix that may work (haven't tested it)
String firstname = "";
for (int i = 0; i < names.length; i++) {
int amount = 0;
boolean skip = false;
for (int j=0; j < names.length; j++) {
//need to skip because we have already processed it
if(names[j].equals(names[i]) && i > j) {
skip = true;
break;
}
else if (names[j].equals(names[i])) {
amount += scores[j];
}
}
if(!skip) {
System.out.println(names[i] + " " + amount);
}
}
If you make an array or list of the Person class you can implement Comparable and add a method to help in sorting.
Java is an object-oriented language, which means, among other things, that you can make your own data structures. Using parallel arrays is error prone, and it separates data you want to keep together. So, what do you need to organize this?
First is a way of storing a name and an amount. Call it Donation.
class Donation {
private final String name;
private final int amount;
public Donation(String name, String amount) {
this.name = name;
this.amount = amount;
// EXERCISE: Add error checking.
}
public String getName() { return name; }
public int getAmount() { return amount; }
public String toString() {
return "Name: " + name +", amount: " + amount;
}
}
Notice that this class's variables are final; they can't be changed once set. They are set in the constructor, and there are get methods and a toString method that replaces what you have in your System.out.println statement.
Next, you need a way of storing the data. Don't use arrays. Lists are more flexible.
private static List<Donation> donations = new ArrayList<Donation>();
// and in main:
while (true) {
String name = null;
int amount = 0;
if (in.hasNext()) {
name = in.next();
} else {
break;
}
if (in.hasNextInt()) {
amount = in.nextInt();
} else {
break;
}
donations.add(new Donation(name, amount));
} See -- no 4s.
Next, you need to consolidate the repeated donations. I mean, some people give to their church every Sunday. We'll use the appropriate structure, a Map.
// Also in main:
Map<String, Integer> totals = new HashMap<>();
for(Donation d: donations) {
String name = d.getName();
int amount = d.getAmount();
if (!totals.containsKey(name)) {
totals.put(name, 0);
}
int currentDonation = totals.get(name);
totals.put(name, currentDonation + amount);
}
And then finally, you iterate through the map and print each entry.
for ( Map.Entry<String, Integer> entry: totals.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
And now, another exercise and strategy: stop doing everything in main. Give your ChapterFive class instance variables and methods. Then, write tests for these. Try to find improvements to what I suggested. Then, see if there are libraries that can help you.