Increasing array length dynamically while adding objects to array - java

I wrote a method that adds an object to an array of objects. If the array gets full, it should make a new array and double the old array size using Arrays.copyOf. However, it results in successfully increasing the array size, but it fills the new slots with duplicates of the last object from the old array.
Here is the add method from the ClassRoster class:
void add(Student newStudent){
int i=0;
while(i != classSize){
if(roster[i] == null{
roster[i] = newStudent;
break;
}
if(i>=roster.legnth){
Student[] newRoster = Arrays.copyOf(roster, 2*roster.length);
roster = newRoster;
}
i++;
}
}
The ClassRoster class also has a constructor that is initialized with an array size of 10.
public class ClassRoster{
private Student[] roster;
final int SIZE = 10;
public ClassRoster(){
this.roster = new Student[SIZE];
}
The main method uses this method to add Student objects from an input text file:
ClassRoster firstRoster = new ClassRoster();
scan = new Scanner(inputFile).useDelimiter(",|\\n");
while(scan.hasNext()){
String name = scan.next();
int gradeLevel = scan.nextInt();
int testGrade = scan.nextInt();
Student newStudent = new Student(name,gradeLevel,testGrade);
firstRoster.add(newStudent);
System.out.printf(firstRoster.toString());
}
The text file would look like this:
John,12,95
Mary,11,99
Bob,9,87
Larry,10,90
Steph,11,89
James,12,95
Susan,11,88
Harry,9,78
Ann,10,92
Holly,9,86
Sammy,12,75
Jen,11,90
Katrina,9,94
However, the program produces an output like this:
John,12,95
Mary,11,99
Bob,9,87
Larry,10,90
Steph,11,89
James,12,95
Susan,11,88
Harry,9,78
Ann,10,92
Holly,9,86
Holly,9,86
Holly,9,86
Holly,9,86
It seems to that it just copies the last object of the old array after it reaches its maximum size of 10. After Holly, it doesn't print out the rest of the students.
SOLUTION
Figured out the problem. The array was never doubled or increased in size. The array still has a size of 10 because it never reenters the while loop in the add method since while(i != classSize) is now false. Therefore, the code never reaches the if (i>=roster.length) portion of the method and does not increase the size of the array. The program kept printing duplicates of Holly because scan.hasNext() was true. It kept returning the last object in the array to the
System.out.printf(firstRoster.toString());. It was just printing to the console but not actually being assigned to an index in the array.
For the solution, I just modified the while statement in the add method:
while(i != classSize || i >= roster.length)

If classSize is the same as roster.length then you should change its value when you double the size of the array (although you should not keep a separate variable since you have roster.length unless you need it for something else).
When you double the size of the array then you can add the new item at the classSize position (classSize is still equal to the previous size) and break the loop:
void add(Student newStudent){
int i=0;
while(i != classSize){
if(roster[i] == null{
roster[i] = newStudent;
break;
}
if(i >= roster.legnth){
Student[] newRoster = Arrays.copyOf(roster, 2 * roster.length);
roster = newRoster;
roster[classSize] = newStudent;
classSize = roster.length;
break;
}
i++;
}
}

SOLUTION
Figured out the problem. The array was never doubled or increased in size. The array still has a size of 10 because it never reenters the while loop in the add method since while(i != classSize) is now false. Therefore, the code never reaches the if (i>=roster.length) portion of the method and does not increase the size of the array. The program kept printing duplicates of Holly because scan.hasNext() was true. It kept returning the last object in the array to the System.out.printf(firstRoster.toString());. It was just printing to the console but not actually being assigned to an index in the array.
For the solution, I just modified the while statement in the add method:
while(i != classSize || i >= roster.length)

Related

Remove duplicates from array by adding non-duplicates to new array

I need to remove duplicate elements from an array by adding elements that are not repeated in the original array to a new array and output the contents of that.
The problem I am having is that when the new array with no duplicates is printed there are zeros being outputted also.
Thus: does Java fill the array with zeros?
public static boolean hasDuplicates(int arrayNum[])
{
boolean dupFound = false;
int ctr1 =0;
while (ctr1<arrayNum.length && !dupFound)
{
int ctr2 = ctr1+1; // be 1 ahead each time ctr1 increments
while(ctr2<arrayNum.length)
{
if(arrayNum[ctr1] == arrayNum[ctr2])
dupFound = true;
ctr2++;
}
ctr1++;
}
return dupFound;
}
public static int[] removeDuplicates(int[] arrayNum)
{
if(hasDuplicates(arrayNum) == false)
return arrayNum;
else
{
int outArray[] = new int[arrayNum.length];
int ctr1=0;
int ctr2 = ctr1+1;
int index = 0;
boolean dupFound = false;
while(ctr1<arrayNum.length)
{
dupFound = false;
ctr2 = ctr1+1;
while(ctr2<arrayNum.length && !dupFound)
{
if(arrayNum[ctr1] == arrayNum[ctr2])
dupFound = true;
ctr2++;
}
if(dupFound == false)
{
outArray[index] = arrayNum[ctr1];
index++;
}
ctr1++;
}
return outArray;
}
}
public static void testRemoveDuplicates()
{
Scanner input = new Scanner(System.in);
System.out.println("Enter size of input array");
int array[] = new int[input.nextInt()];
System.out.println("Enter number of ints required");
for(int i=0; i<array.length; i++)
{
array[i] = input.nextInt();
}
int outArray[] = new int[array.length];
outArray = removeDuplicates(array);
for(int i=0; i<outArray.length; i++)
{
System.out.println(outArray[i]);
}
}
Here:
int outArray[] = new int[array.length];
That code assumes that you have exactly array.length array elements in your output array. And that is of course a too high number! The point is: when you create a new array of that size, the whole array is initially populated with 0 values. And your code will only "overwrite" a few slots of that output array; and all other slots stay at their initial 0 default value.
The point is: you first have to compute how many duplicates you have in your input array; and then you create a new array with exactly that number.
Alternatively, you could be using List<Integer> instead of int[]; as Java collections have the ability to grow dynamically. (or, you can keep increasing that array for collecting duplicates "manually"; that can be done, too - just a bit of complicated code to get there).
And the direct immediate answer is: yes, exactly - Java arrays are "pre-filled"; see here.
You can fix all of your problems (and probably make the code substantially faster in the process since it'll no longer have quadratic complexity) by using standard Java API calls to store the unique elements in a Set, and then turn the values in that set back into an array.
The main caveat is that you'd need to use Integer rather than int:
Set<Integer> s = new LinkedHashSet<Integer>(Arrays.asList(inputArray));
Integer[] outputArray = s.toArray(new Integer[0]);
The LinkedHashSet preserves insertion order, so you'll get the elements back in the same order as they originally appeared albeit without the duplicates.
May be you are wasting too much memory here by considering the worst case scenario where all input given are different while declaring the output array size. More Optimized Approach is that you can have an List<Integer> or ArrayList<Integer> which can store the unique values and then at last , If you want unique values in Array than declare the ArraySize same as the ArrayList<Integer> or List<Integer> size and just in one linear loop , You can copy all the data.
Does Java fill the array with zeros?
Yes , Whenever you declare the integer array , It will be having all its elements as 0. If you want to reset the value of Array to a particular value , You can use this method Arrays.fill(int array[] , int default_value). This can be done in O(list_size) complexity which is linear.
For your purpose more better approach would be use of HashSet<Integer> which holds only unique elements and which is Dynamic in nature so no need to waste extra space as well as it can make your work very easy.
So first you need to all elements in the HashSet<Integer> and then by using Iterator you can easily iterate through it but the insertion order can be disturbed here. So as replied by #Alnitak You can use LinkedHashSet<Integer> to have insertion order same.
A sample code using HashSet :
HashSet<Integer> set=new HashSet<Integer>();
int total_inputs=sc.nextInt();
for(int i=0;i<total_inputs;i++)
set.add(sc.nextInt());
Iterator itr=set.iterator();
while(itr.hasNext())
System.out.println((int)itr.next());
Note : Here input order will not be preserved.
Does Java fill the array with zeros?
Yes, java will initialize every element of your int array to 0. Therefore using arr.length will not work for you as it doesn't return the logical length of your array. You need to track the number of elements of your array yourself. The following line in your code has no meaning
int outArray[] = new int[array.length];
because outArray starts pointing to a different array as returned by your method removeDuplicates.
I need to remove duplicate elements from an array by adding elements
that are not repeated in the original array to a new array
The easiest thing you can do is the following way:
In your method removeDuplicates,
Find the highest number from the given input array, increment it by 1 and assign it to a variable.
int max = Arrays.stream(arrayNum).max().getAsInt() + 1;
Modify your if block from
if(arrayNum[ctr1] == arrayNum[ctr2])
dupFound = true;
to
if(arrayNum[ctr1] == arrayNum[ctr2]) {
dupFound = true;
arrayNum[ctrl] = max;
max++;
}

Can you remove an element from an array by placing it at the end of the array and decreasing the size of the array?

for(int i = 0; i < bag.length; i++)
{
if(bag[i].equals(a))
{
tmp = bag[i];
bag[i] = bag[bag.length-1];
bag[bag.length-1] = tmp;
numElements--;
break;
}
}
The goal of this is to find an object in the array and then remove it? is it possible??
Changing the length of an array is not possible. Recall that array is a static data structure whose size is determined before hand. Increasing or decreasing is not supported in this data structure. The fact that one has to increase or decrease the size depending on the usecase means that they have picked up the wrong data structure. They should perhaps go with an ArrayList.
Anyway, coming back to your question, you can simulate the 'size decrease' by maintaining a variable which you let track the array index and decrease the size of this variable. This lets you give the impression of shrinking the array.
The code you have provided does the same. Note however, that you should be using this modified index to track the contents of your array.
for(int i = 0; i < bag.length; i++)
{
if(bag[i].equals(a))
{
tmp = bag[i];
bag[i] = bag[bag.length-1];
bag[bag.length-1] = tmp;
numElements--;
break;
}
}
Whenever a particular bag at a given index equals to the item under question i.e., 'a', we swap elements so that the current bag element to be removed moves to the last and also we reduce the size of our new index - numElements by 1 to simulate this.
If you have the full code with you, please consider adding the following snippet at the end of that program to understand this more:
// Simulation of the array shrinking.
for(int i = 0; i < numElements; i++)
{
System.out.println( bag[i] );
}
// Movement of uninteresting elements to the end of the array.
for(int i = 0; i < bag.length; i++)
{
System.out.println( bag[i] );
}
It's not possible to change the length of an array. You can overwrite the element you wish to remove with the last element of the array and then copy the first bag.length - 1 elements of your array to a new array whose length is bag.length - 1.
for(int i = 0; i < bag.length; i++) {
if(bag[i].equals(a)) {
bag[i] = bag[bag.length-1];
bag = Arrays.copyOf (bag, bag.length - 1);
break;
}
}
public static String[] removeElements(String[] input) {
List<String> result = new ArrayList<String>();
String deleteValue = "somevalue";
for(String item : input)
if(!deleteValue .equals(item))
result.add(item);
return result.toArray(input);
}
This is one method you can fit this into your program.
You cannot decrease the size of an array. okay no problem! you can create your own data structure which supports that right?
Now, create a class named say MyArray with functions like increaseLenght(int) and decreseLength(int). Try it if you want to, will be fun for sure..
You cannot reduce the size of an array. Arrays are fixed length. What you can do is have a variable that indicates how many entries of the array you are using. This is what you are doing with numElements. The standard class ArrayList is implemented like this. The data is kept in an array and a private field size is used. With an ArrayList, when you remove an element, all the elements to the right are shifted left. However I also like your idea.
I would suggest 2 changes.
Make the last element null instead. If you are removing the element, why does it still need to be in the array?
Use numElements - 1 rather than bag.length-1 as the array could be bigger.
With these changes it becomes:
for(int i = 0; i < bag.length; i++)
{
if(bag[i].equals(a))
{
bag[i] = bag[numElements-1];
bag[numElements-1] = null;
numElements--;
break;
}
}

Java - Trouble reading data from a list of 2D arrays

I have created a list of 2D arrays containing randomly generated number values for different locations.
public static int Prices[][] = new int[Cities.length][ItemNames.length];
public static List<int[][]> CityPrices = new ArrayList<int[][]>();
public static void NewDay()
{
for(int i = 0; i<Cities.length; ++i)
{
Prices[i] = PriceGenerator.ReturnPricesForCity(i);
//This method returns an array of random integers
}
CityPrices.add(Prices);
}
But then later when I want to retrieve the price history for a specific item for the amount of days passed, it returns the same value for each day
int Prices[] = new int[GlobalVariables.CityPrices.size()];
String sTest = "";
for(int i = 0; i < Prices.length; ++i)
{
Prices[i] = GlobalVariables.CityPrices.get(i)[spinCity.getSelectedItemPosition()][spinItem.getSelectedItemPosition()];
sTest = sTest + Prices[i] + ",";
}
In this case, the values returned by sTest was : 6055,6055,6055,6055,6055, for five consecutive days.
If I would for instance add a day, the values would change to a range of a new number, which in this case was : 7294,7294,7294,7294,7294,7294,
Please show me what I am doing wrong, as I have been trying to figure this one out the past 4 days with no luck.
Every element in your CityPrices list is the same: in each case, you are adding the Prices two-dimensional array. Your loop modifies Prices[i], but it doesn't change Prices, which is still a reference to the same two-dimensional array right the way through.
I think you're imagining it will pass the contents of the array in its current state, but it doesn't: it passes a reference to the array to the .add() method, so any subsequent changes to the array will be reflected in the contents of CityPrices.
If at the end of your loop you try
CityPrices.get(0) == CityPrices.get(1)
you'll see it returns true.
In the assignment: Prices[i] = GlobalVariables.CityPrices.get(i)[spinCity.getSelectedItemPosition()][spinItem.getSelectedItemPosition()]; you are basically referencing an int[][] at the same index for both dimensions.
On top of that, the spinCity.getSelectedItemPosition() invocation might be returning the same index at every iteration of your loop, hence your identical values.
It's hard to assume anything further as you haven't posted the code for spinCity.

Java Array Creation and Array Name Change

Can you create a line of code, within a while-loop, that will create a new array AND change the array's name with each iteration of the while loop?
Example:
int size = 10;
int name_count = 1;
while(size <= 100)
{
//name_count is changing the name of the array by calling it
// "array1", "array2", etc...
//I know this may not be correct code for changing the name of
// the array, but it is suppose to get the point across.
int[] array(name_count) = new int[size];
for (int i = 0; i <= size; i++)
{ /* Adding numbers to an array */ }
size = size + 5;
name_count++;
}
Identifier names need to be defined at compile time. So you can't explicitly use a different variable name on each iteration of the loop.
Another problem with your pseudo-code is that, if the array were to be declared inside the loop, it would fall out of scope when the loop completes, so there wouldn't be much point.
To do something like this you need to use some collection to hold the arrays, and it would be easier to make them explicit objects instead of just arrays. Something like:
List<List<Integer>> listOfArrays = new ArrayList<List<Integer>>();
while (size <= 100) {
List<Integer> listOfNumbers = new ArrayList<Integer>(size);
/* insert loop here to add numbers to listOfNumber */
size += 5;
name_count += 1;
}
Then you can access each list of numbers using an index into listOfArrays -- equivalent to naming each one with the index, but handled at runtime instead of compile time.
You cannot change the array's name, It will just re-declare the array with each successful loop. (It will be a new blank array.) I think what you are looking for is a two dimensional array.
int[][] myArray = new int[3][3];

Loop/array (Java)

I am having some problems in getting a loop to work. My goal is to create a loop which will allow the user to fill in lottery numbers in several rows (the user may decide how many rows he/she wants to fill out, but it can not be more than a maximum number specified earlier in the code). So far, my code is as follows:
import java.util.Scanner;
public class LotteryTicket {
public LotteryRow[] rows;
public int numberOfRows;
public Player ticketOwner;
public LotteryTicket(int maxNumberOfRows) {
this.rows = new LotteryRow[maxNumberOfRows];
}
Scanner input = new Scanner(System.in);
public void fillInTicket() {
System.out.print("How many rows do you want to fill in? ");
int n = input.nextInt();
while (n < 1 || n > rows.length) {
System.out.println("The number of rows must lie between 1 and " + rows.length);
System.out.print("How many rows do you want to fill in? ");
n = input.nextInt();
}
for (int index = 0; index < n; index++) {
rows[index].fillInRow();
}
numberOfRows = n;
}
When I try to run this in a main-method, and I enter a proper number of rows, I get the error message:
Exception in thread "main" java.lang.NullPointerException
at LotteryTicket.fillInTicket(LotteryTicket.java:24)
Line 24 is the line in which I call upon the fillInRow()-method which I have created in another class, so I suspect the problem lies here. I know that this method works fine, as I have tried it in a test program. However, am I not referring correctly to this fillInRow()-method?
Any help will be much appreciated!
You created an array with size maxNumberOfRows, but you haven't populated it with any objects. It initially just contains null references.
To fix the code, you have to call the LotteryRow constructor to create an object and then put a reference to that object in your array. You can fix your code like this:
for (int index = 0; index < n; index++) {
rows[index] = new LotteryRow();
rows[index].fillInRow();
}
You must create a new object and place it in the array before you call a method on it. Java arrays of objects are initialized to all nulls.
You never initialize rows. Yes, you create the Array with this.rows = new LotteryRow[maxNumberOfRows]; but that does NOT create a new LotteryRow Object for every Array Entry, so the whole array is filled with null. You have to create the LotteryRow Objects by yourself

Categories