How can I manipulate 2D arrays in Java? - java

I've been studying for my upcoming Java exam, and i'm having a hard time wrapping my head around 2D arrays. I have the basics down, such as creating and initializing a 2D array, but when it comes to inserting, deleting, or even sorting through one, I get pretty confused. My professor spent all of 10 minutes going over the basics but on our exam, we are expected to know how to create a 2D array of objects and manipulate the data by inserting, deleting, and sorting the objects in the array. He makes us hand-write all of our code on our exams, so no computers are allowed to assist in the process. I've spent hours pouring over examples both here and on other sites, but I still don't feel like I understand the material well enough to hand write all my code and get it right.
My confusion mostly stems from the nested for loops usually used to move thru a 2D array. I can see how other people do it and copy that, but I still don't understand why the loops work as they do. I'm sure i'm in the minority here, but for whatever reason the logic behind it has me completely lost.
Take this(albeit poor) example i've been working on to help myself understand 2D arrays(as well as the rest of the exam material). Say you run a car dealership and you want to order cars to fill your stock. The program starts with a top abstract class that describes the cars you are selling in general(in my case Audi). The dealership offers 4 models of Audi's, an A4, A6, A8, and R8. All these cars(classes) inherit methods from the super, named Audi. I then want to create a 2D array to store the cars in stock. This will be used in another class defined by me, including methods to search(), delete(), and sort(). Let's call it AudiDealership. The dealer can only hold 3 of each model, so the array would be something like Audi[4][3]. The A4's would fill the first row, subscript 0, A6 fills subscript 1, ect. How would I set up the for loops to insert/delete from the proper row? I obviously don't want an A4 inserted into a row that should hold an A6, and so on.
Again, I can stare at code all day and copy it, but I want to understand why/how the loops work as they do. I apologize if this topic seems trivial or has been beaten to death, but all the reading i've done before posting this has left me just as confused as before. Many of you on this site are fantastic teachers in your own right, so I thought someone may be able to explain this in a way that I can understand. My professor hasn't been any help in this regard, so i'm using external means to try and figure things out. I greatly appreciate any advice or explanation in advance :)

It helps to think of 2D arrays as arrays that hold other arrays. Such as Cars[0][5] is accessing a car array at 0 and the actual car is found in position 5 of that array. Cars[1][5] would access the second car array at position 1 and the car is found at 5 of the array that's in position 1. This code might help you understand it a bit more:
public class TwoDArray {
public static void main(String[] args)
{
Cars[][] cars; // declaring my 2D array.
cars = new Cars[4][]; // making the x axis 4 cars wide.
// now we will step along the x axis and create a Cars array in each slot.
for ( int a = 0; a < cars.length; a++) // cars.length = how wide.
{
cars[a] = new Cars[3]; // creating a new Cars[] in each slot of our 2D Car array # position a.
//cars[a] = new 1D Cars array in slot a, length of 3.
}
// Note that we could have also created our array like this.
// Cars[][] cars = new Cars[4][3];
for ( int x = 0; x < cars.length; x++) //stepping along the x axis. cars.length = how wide.
{ //every time we step thru x we will execute this next loop.
for ( int y = 0; y < cars[x].length; y++) // stepping along the y axis. cars[x].length = how long.
{ // this loop will cycle through the y axis each time we increment x
cars[x][y] = new Cars( 2014, "someAudi", x + " " + y ); // creating a new car(s) # x,y position.
}
}
// now to just print them.
for ( int x = 0; x < cars.length; x++) //stepping along the x axis again.
{
for ( int y = 0; y < cars[x].length; y++) // stepping along the y axis.
{
System.out.println(cars[x][y].getYear() +
" " + cars[x][y].getModel() +
" " + cars[x][y].getName() +
" " + cars[x][y].getManufacturer()); // the super method.
}
}
//INSERTION.
// To insert into your array, you simply need to provide the coordinates to insert the new Car(s) object.
// This next line will insert a new Car into the array at position 1 and the number 2 element of that array.
cars[1][2] = new Cars( 2014, "someAudi", "My Favorite Car!");
System.out.println(); // Just adding a space between outputs.
for ( Cars[] c: cars) //extracting each Cars array and name it c from the 2D Cars array named cars.
{ //basically stepping along the x axis and getting each array stored in x.
for ( Cars car: c) // Now we are stepping along the y axis.
{ // We are getting each individual Cars object and naming it car
// from each Cars[] named c from our first loop.
System.out.println(car.getYear() +
" " + car.getModel() +
" " + car.getName() +
" " + car.getManufacturer()); // the super method.
}
}
// NOTE* if you wish to insert a new element and do not have extra capacity then you will need to
// create a larger array # cars[x]. cars[x] = new Cars[newSize];.
// DELETION.
// To delete an element you can just simply overwrite it.
// such as:
cars[1][1] = new Cars( 2014, "someAudi", "new Audi"); // Essentially we deleted and inserted a new object
// at position [1][1].
// If you just want to completely remove the element then you will need to update the size of the array.
// You can define a new array to hold the values of the old array minus the element that should be deleted.
Cars[] newArray = new Cars[cars[2].length - 1]; // We will use the array stored in cars[2] for this example.
// we set the length to one less to completely get rid of the
// old element.
int deleteThisPosition = 1; // We will use this variable to store the position that will be deleted from
// the array stored in cars[2].
int newArrayPosition = 0; // We will use this to increment our position in the new array along with `a`
// in the next for loop.
for ( int a = 0; a < cars[2].length; a++)
{
if ( a == deleteThisPosition) // if it reaches this position we will advance `a` and exclude it from
a++; // our new array.
newArray[newArrayPosition] = cars[2][a]; // we will store the value # position `a` from the array in cars[2]
// into our newArray # position `newArrayPosition`.
newArrayPosition++; // incrementing our variable to stay parallel with the array in cars[2].
}
//Now we can just assign the newArray to cars[2]. You will notice that Car `2 1` is no longer present.
cars[2] = newArray;
System.out.println(); // Just adding a space between outputs.
for ( Cars[] c: cars)
{
for ( Cars car: c)
{
System.out.println(car.getYear() +
" " + car.getModel() +
" " + car.getName() +
" " + car.getManufacturer()); // the super method.
}
}
}
}
Here are the other classes from your example.
Audi class:
public abstract class Audi {
public String getManufacturer() { return "Audi"; } // method from this super class.
}
Cars class:
public class Cars extends Audi{ //extending Audi.
private String model;
private String name;
private int year;
Cars(int year, String model, String name)
{
this.year = year;
this.model = model;
this.name = name;
}
public String getName() { return name; }
public String getModel() { return model; }
public int getYear() { return year; }
}
If you run the code you will notice the pattern in the names of the cars.
Output:
Notice the pattern in each car's name, the unique column. It corresponds to how we stepped through our loops. We started with x and for each x we looped through y. x + " " + y was how we named each car in the code above.

Audi[4][3] cars = ... // your 2D array of all cars
As you correctly specified,
The A4's would fill the first row, subscript 0, A6 fills subscript 1, ect.
which translates to cars[0] holds Audi[] with A4 instances, cars[1] holds Audi[] with A6 instances etc.
OK, so
Audi[] A4s = cars[0];
Audi[] A6s = cars[1];
...
Then you could say that
Audi A4_1 = A4s[0];
Audi A4_2 = A4s[1];
Audi A4_3 = A4s[2];
...
And repeat it for each car you have. But this is a wrong approach. First we generalize access to each car.
If you want to traverse specific cars in each model array, you need to have a for-loop with index called, say, specificCarIndex. Loop to traverse an array of A4s will be simple:
for (int specificCarIndex = 0; specificCarIndex < 3; specificCarIndex++) {
// Here A4s[specificCarIndex] contains an object of concrete Audi car of model A4
}
To traverse array of another model (like A6) you do the same, replacing A4s with A6s and so on.
Now we need to generalize everything.
for (int carModelIndex = 0; carModelIndex < 4; carModelIndex++) {
// Here cars[carModelIndex] holds an array of specific Audi model as you mentioned before
}
cars[carModelIndex] essentially is Audi[] A4s if carModelIndex == 0, then Audi[] A6s if carModelIndex == 1 and so on.
Now that we know how to access array of each Audi model, and we know how to access individual cars in each model array, we combine the two:
for (int carModelIndex = 0; carModelIndex < 4; carModelIndex++) {
for (int specificCarIndex = 0; specificCarIndex < 3; specificCarIndex++) {
// Here cars[carModelIndex][specificCarIndex] holds an object of type Audi which refers to a specific car
// If double index seems difficult, consider this:
// Audi[] audis = cars[carModelIndex] (array like A4s, A6s...)
// Audi audi = audis[specificCarIndex] (specific car)
// Just as in the examples before for-loops.
}
}

Let me give you an example:
StringBuilder output = new StringBuilder();
for (int i = 0; i < table.length; i++) {
for (int j = 0; j < table[i].length; j++) {
output.append(table[i][j]);
}
output.append("\n");
}
This would be the code to loop through a 2 dimensional array.
The code goes directly into the first row. This is the i-value.
As you want to loop through every column of the row,
you need to know the length of the row to loop through it.
So you start in the first row, and go right to the end which is table[i].length.
In the first row the first length would be table[0].length.
And this length is 3 as you have 3 columns in each row.
As we're now done with looping through the first row, we get to second row.
By going into the second row i increases by one.
So our pointer shows now in row 2 (The i in table[i].length is now 1 because it always starts at 0) and so on.
Our pointer goes through every row and thats just how it works.
with every new row the pointer of i increases by 1 (that's the i++ in the for loop).
With every new column in one row the j increases and the i stays the same.
The i only changes when you're entering a new row.
And the j changes by entering a new column.
Hope this helps ;)
EDIT.:
Another example :
if you would like to get the value of the 3rd column in the 4th row:
The value you want is inside here: table[3][2];
Remember arrays always start counting at 0. :)

Related

How to check if a traversion has reached a certain Index in a 2D-Array in Java?

Let's say we have a 2D-boolean Array as a presentation of a maze, the size of the Array is not fixed and random. The walls are depicted as true:
boolean[][] mazeArray = new boolean[width][height];
The exit of the maze is at a fixed Index. How can I check wether the traversion has reached this certain index or not?
My idea was to create an int[ ] to keep track of the position, it gets updated and overwritten with every step:
int[] location = {1,0};
... But I don't understand why my check in the while-loop doesn't work:
while( location[0] != (maze[0].length-1) && location[1] != (maze[1].length-2) ) {
// traversion with pledge algorithm
}
You're making everything so much harder for yourself. Go easier ways.
Use simpler locations handling
Instead of a location[], simlpy use int destinyX and int destinyY. And as your current position, you should use int positionX and int positionY.
If you'd like the OO-stlye more, or maybe wanna keep the gates open for a solution in 3D or n-D, you could introduce a Location class that has X and Y, and all movement and checks could be handled by that class. Then you'd have Location targetLocation = new Location(x,y); and your current position as Location currentPosition = new Location(x,y);. You then could check with if (currentPosition.equals(targetLocation))...; or in your case while(!currentPosition.equals(targetLocation)) {...}
It seems you have misunderstood the array.length function, or you're using it in an awfully inconvenient way.
At the moment you're blindly shooting at the array lengths of maze[]. This is bad for 2 reasons:
array lengths should not have anything to do with positions inside the array (logical paradox), and
because you could never freely move your destination, it would always stick to the right or bottom outsides of the maze
Use the positioning above, this will clear up that problem.
Suggestion: use a byte[][] or enum[][] for maze
At the moment, you only know if you have a wall at a certain location. If you wanna include other elements, like water, treasure, or the target location, wormholes etc, then you should either:
Use a byte[][] and fill it with values
value 0 could be pathways
value 1 could be walls
value 2 could be the exit
value 3 could be the water etc.
Use constants, like static public final int WATER_CODE = 3;
Or, alternatively, create your own enum:
public enum LocationType {PATH, WALL,EXIT,WATER}
and then have maze be like:
LocationType[][] mazeArray = new LocationType[width][height];
and everything is PATH in the beginning, and you can set up WALLS like this:
mazeArray[x][y] = LocationType.WALL;
or water:
mazeArray[x][y] = LocationType.WATER;
Use class or interface for maze[][]
For the sake of Wormhole or extended functionality, you could also use a class instead of an enum:
abstract class LocationType {}
and then implement certain types, like
class Wall extends LocationType {}
or even
class Wormhole extends LocationType {
public Location leadsTo() { /* */ };
}
and
class Treasure extends LocationType {
public int getAmoundOfGoldCoinsFound() { /* */ };
}
If you implement LocationType as an interface, replace 'extends' by 'implements'
The problem with your code is that you check wrong items in your maze array:
maze[0] is the first "line" of your 2d-array
maze[1] is the second "line" of your 2d-array
Proper way of traversing 2d-array is following (I've replaced your location array with separate x and y variables to better visualize the algorithm).
My algorithm enters the 2d mazeArray line by line and then iterates each line's elements.
public class Maze {
public static void main(String[] args) {
int width = 20;
int height = 20;
boolean[][] mazeArray = new boolean[width][height];
int x = 0;
int y = 0;
while (y < mazeArray.length) {
while (x < mazeArray[y].length) {
System.out.println("Traverse at (" + x + ", " + y + ")");
x += 1;
}
x = 0;
y += 1;
}
}
}

Finding the element with the lowest difference in an ArrayList when compared to a constant

I am trying to have this code determine which element has the closest value to a constant.
In this code the variable boxes = 5, any element that has boxCapacity >= boxes is added to an ArrayList. From that list, the one with the closest boxCapacity to boxes should be used. I am able to select those greater than boxes, but unable to pick that with the closest boxCapacity.
public void deliver(double miles, int boxes) {
for (int i = 0; i < cars.size(); i++){
if (cars.get(i).getBoxCapacity() >= boxes){
deliveryCars = new ArrayList<Car>();
deliveryCars.add(cars.get(i));
smallest = deliveryCars.get(0).getBoxCapacity();
for(j = 0; j < deliveryCars.size(); j++){
if (deliveryCars.get(j).getBoxCapacity() < smallest) {
smallest = deliveryCars.get(j).getBoxCapacity();
k++;
}
}
}
}
System.out.println("Delivering with " + deliveryCars.get(k).getPlate());
}
I tried to make a new list, but it has not been working out.
You can simplify your code to something that looks like that
public void deliver(double miles, int boxes){
// check if there are cars availible
if (!cars.isEmpty()) {
// assume that first car in a list is best for delivery
int smallest = cars.get(0).getBoxCapacity();
Car deliveryCar = cars.get(0);
// iterating over all cars in a list
// but still compares to the first car in a list
for (Car car : cars) {
if (car.getBoxCapacity() >= boxes
&& car.getBoxCapacity() < smallest) {
deliveryCar = car;
}
}
System.out.println("Delivering with " + deliveryCar.getPlate());
}
}
Using Java 8 streams...
Car deliveryVehicle = cars
.stream()
.filter(c -> c.getBoxCapacity() > boxes)
.min(Comparator.comparingInt(Car::getBoxCapacity))
.orElse(null);
Assuming your cars was an iterable/streamable collection, this creates a stream, filters it to extract all instances where the capacity is greater than boxes, finds the element with the smallest capacity, and returns it, or null if there were no cars with more than boxes capacity.
You can then do whatever you want with the returned Car object, like call getPlate(). Remember to check for null for the case where no acceptable car was found.
This answer builds from the clarifications that #DataDino provided, namely that the goal is to find the car with the lowest boxCapacity that is greater than the targetCapacity.
Given the list of cars, you can filter out any car with a boxCapacity smaller than the target, and then select the minimum boxCapacity from what is left.
List<Car> cars = List.of(new Car(8), new Car(3), new Car(5), new Car(6));
int suggestedCapacity = 4;
Optional<Car> bestFit = cars.stream()
.filter(car -> car.getBoxCapacity() >= suggestedCapacity)
.min(Comparator.comparing(Car::getBoxCapacity));
if (bestFit.isPresent()) {
System.out.println("found car with capacity " + bestFit.get().getBoxCapacity());
} else {
System.out.println("No suitable car found");
}
The Streams api takes care of the list manipulation and keeping track of the internal state of the minimum for you.
You do not need a new list. The task you've outlined is a sequential search through an unordered list, and unless I misunderstand your goal, you only need a single for loop -- that is, you only need to iterate through the list one time. Since you are looking for a single item and you don't need to look at more than one item at a time to see if it's the best one so far, you only need one variable to keep track of its location in the list.
Here's a working sample. Notice the variable names describe the purpose (e.g. "mimimumBoxCapacity" instead of the ambiguous "boxes"). This helps me better understand what my code is doing.
// print the plate number of the car with the smallest boxCapacity
// greater than a specified minimum
public void deliver(List<Car> cars, double miles, int minimumBoxCapacity)
{
if ((cars != null) && (cars.size() > 0))
{
int indexOfBestMatch = -1; // negative index means no match yet
for (int i = 0; i < cars.size(); i++)
{
if (cars.get(i).getBoxCapacity() > minimumBoxCapacity)
{
if (indexOfBestMatch < 0)
{
// this is the only match seen so far; remember it
indexOfBestMatch = i;
}
else
{
// found a better match; replace the old best match
if (cars.get(i).getBoxCapacity() < cars.get(indexOfBestMatch).getBoxCapacity())
{
indexOfBestMatch = i;
}
}
}
}
if (indexOfBestMatch >= 0)
{
System.out.println("Delivering with " + cars.get(indexOfBestMatch).getPlate());
}
}
}
This code illustrates how your algorithm would need to change to do what you want. DataDino's answer using a Car variable to keep track of the best fit is even clearer, especially where the method returns a Car result and lets the calling logic decide what to do with that result.
(Your original code didn't compile, because variables like "smallest" and "deliveryCars" weren't defined before they were used. It would be helpful in the future if you post code that compiles, even if it doesn't yet do what you want it to do.)
So I think what you're saying is that you have of list of values say [0, 1, 2, 3, 4, 5, 6] and then you are given another number say 4, and what you want to do is to select the number from the list that is the smallest of all the numbers greater than 4, so in this case you'd want to choose 5, right?
Well, there are a ton of ways to do that. But the fastest way to do it is to go through the list one time and keep track of the smallest number greater than your 'targetNumber':
...
public Integer getNextBiggest(List<Integer> numbers, int targetNumber)
{
// Set the default 'nextInt' to the largest possible value.
int nextInt = Integer.MAX_VALUE;
for (int i = 0; i < numbers.length; i++) {
// If the current number is greater than our targetNumber.
if (sortedList.get(i) > targetNumber) {
// Set the nextInt variable to the MINIMUM of current number
// and the current nextInt value.
nextInt = Math.min(nextInt, sortedList.get(i));
}
}
return nextInt;
}
...
So that would work, but your list is a bit more complicated since you're using Objects and not integers, that said, it's a simple conversion:
First some assumptions:
cars is a List.
Car object has a getBoxCapacity() method that returns an int.
Car object has a getPlate() method that returns a String.
Ok so it might look like this:
...
public Car getBestFitCar(List<Car> cars, int targetBoxCapacity)
{
// Default best fit is null. No best first yet.
Car bestFit = null;
for (int i = 0; i < cars.length; i++) {
Car current = cars.get(i);
// If the current Car box capacity is greater than our target box capacity.
if (current.getBoxCapacity() > targetBoxCapacity) {
// Set the bestFit variable to the Car that has the MINIMUM
// 'box capacity' between the current Car and the bestFit Car.
if (bestFit == null || bestFit.getBoxCapacity() > current.getBoxCapacity()) {
bestFit = current;
}
}
}
return bestFit;
}
public static void main(String[] args) {
List<Car> cars = new ArrayList<>();
// add some cars here...
int targetBoxCapacity = 5;
Car bestFit = getBestFitCar(cars, targetBoxCapacity);
if (bestFit != null) {
System.out.println("Best fit car is: " + bestFit.getPlate());
} else {
System.out.println("No car can fit " + targetBoxCapacity + " boxes.");
}
}
Update:
I've seen some nice responses using streams, but I'd to add some caution. Streams make writing the code faster/more readable but would end up being less efficient in time/space than a solution with simple loops. This solution only uses O(1) extra space, and O(n) time in the worst case.
I'd figure the stream answers would use O(n) extra space, and O(n * n log n) time in the worst case.
So, if you have a tiny list I'd say go with the simple really cool streams solutions, but you have a list of a lot of elements that you'll be better off with a more traditional approach.

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: Issue Reading Text file then Converting

I've got an issue getting a method to read a file, then converting it to an integer. Here is a brief explanation of the program. It is essentially a car dealership inventory that keeps track of the vehicles in the lot by keeping them written down in a text file. When the program starts it will need to read the file and put all the current cars into an array so they can be displayed. Then the rest of the program will do other things like remove cars and add news ones etc. The part I am at is when the program first starts it needs to read the file, but I can't seem to get it to work.
The text file consists of 6 lines in total; 4 numbers first then 2 words respectively. I want the method to read the first four lines and convert those into integers and store them in a temporary array. Then after that it will read the next two lines and store those in a temporary array as well. Afterwards I take all these stored values and send them to a constructor. The constructor is then stored in an Arraylist and the Arraylist can be accessed anytime. In the output it does all of this just fine. But it wants to run through the method a second time despite barriers in place to prevent this.
Here is the code. Its a class and not the main program. I will try to explain the program as best I can inside the code.
public class Vehicle {
//All the different private variables for the constructors and methods
private int intholder[], year, type, kilometres, price, loop;
private String make, model, myline, holder[];
//The Arraylist that the different vehicle objects will be stored
ArrayList<Vehicle> allCars = new ArrayList<Vehicle>();
//The Default constructor
public Vehicle(){
make = "Vehicle Make";
model = "Vehicle Model";
type = 0;
year = 0;
kilometres = 0;
price = 0;
}
//The constructor that has information sent to it
public Vehicle(int _type, int _year, int _kilometres, int _price, String _make, String _model){
make = _make;
model = _model;
type = _type;
year = _year;
kilometres = _kilometres;
price = _price;
}
//Text file information
/*
* CAR TYPE CODE:
* 1 - Sedan
* 2 - Truck
* 3 - Crossover
* 4 - SUV
* 5 - Sports
*
* There is a total of 6 lines for each car and are as follows
* 1 - int Type integer
* 2 - int Year
* 3 - int Kilometres
* 4 - int Asking price
* 5 - String Make
* 6 - String Model
*/
//The method in question. It reads through the file, converts the integers and stores them,
//stores the strings, and sends all the information to the constructor
public void readCars()throws IOException{
BufferedReader readFile = new BufferedReader(new FileReader("C:/Users/David/Desktop/FinalProject/Carlot.txt"));
//Setting the length of the temporary arrays
holder = new String[2];
intholder = new int[4];
//The main loop in the method.
do{
//Read the first 4 lines of the file and convert them to integers.
//The try catch shouldn't have to be there because the first 4 lines
//of the file are all numbers, but I put it in there to see when it was messing up.
for(int i = 0; i < 4; i++){
myline = readFile.readLine();
try{
intholder[i] = Integer.parseInt(myline);
}
catch(NumberFormatException e){
System.out.println(e);
}
//Had this in here to see how many lines down the file it would go before messing up.
System.out.println(myline);
}
//Loop to store the Strings
for(int i = 0; i < 2; i++){
myline = readFile.readLine();
holder[i] = myline;
System.out.println(myline);
}
//Sends all the data to the constructor
Vehicle V = new Vehicle(intholder[0], intholder[1], intholder[2], intholder[3], holder[0], holder[1]);
//Several if statements to determine which subclass of vehicle it is.
if(intholder[0]==1){
Sedan S = new Sedan();
allCars.add(S);
}
else if(intholder[0]==2){
Truck T = new Truck();
allCars.add(T);
}
else if(intholder[0]==3){
Crossover C = new Crossover();
allCars.add(C);
}
else if(intholder[0]==4){
SUV U = new SUV();
allCars.add(U);
}
else if(intholder[0]==5){
Sports P = new Sports();
allCars.add(P);
}
//Only break the loop if the myline equals null
}while(myline != null);
//if the loop breaks, close the file
readFile.close();
}
Now I think I know where it is going wrong. At the end of the do/while, it checks if "myline" is null. And because the last time it read the file it was still a String the loop continues. The last time it goes through the loop, everything is null so trying to convert the integer is impossible so I get errors. But I have no idea how to get it to read the file at the end of the loop without going to the next line. Here is what the text file looks like.
1
2007
150250
5000
Toyota
Corolla
2
2005
240400
4500
Chevorlet
Silverado
I can't have it read at the end of the loop because if it does and there are still more cars after the one I just did, It goes into the next line when the loop restarts everything is thrown off.
Any help is appreciated, Thanks!
Use a labeled break statement in your for loops to simply exit out of the main do while loop when myline becomes null. The way other objects are being instantiated within the loop doesn't leave much room for easy refactoring hence the use of a labeled break makes sense here.
outerloop:
do {
for (int i = 0; i < 4; i++) {
if ((myline = readFile.readLine()) == null) break outerloop;
// ..
}
for (int i = 0; i < 2; i++) {
if ((myline = readFile.readLine()) == null) break outerloop;
// ..
}
// ..
} while (myline != null);
Maybe you could use a while loop instead of a do-while loop and read the next line from the file before anything else. Something like this:
String myline = null;
while( (myline = readFile.readLine()) != null ) {
// All your logic...
}
readFile.close();
The condition of while loop does the following: first, read the next line of the file with myline = readFile.readLine(). The previous statement returns the value of myline, so now we check that it is not null with the comparison:
(myline = readFile.readLine()) != null

ArrayList of integer arrays

I'm trying to write a simple game where an enemy chases the player on a grid. I'm using the simple algorithm for pathfinding from the Wikipedia page on pathfinding. This involves creating two lists with each list item containing 3 integers. Here's test code I'm trying out to build and display such a list.
When I run the following code, it prints out the same numbers for each array in the ArrayList. Why does it do this?
public class ListTest {
public static void main(String[] args) {
ArrayList<Integer[]> list = new ArrayList<Integer[]>();
Integer[] point = new Integer[3];
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 3; j++) {
point[j] = (int)(Math.random() * 10);
}
//Doesn't this line add filled Integer[] point to the
//end of ArrayList list?
list.add(point);
//Added this line to confirm that Integer[] point is actually
//being filled with 3 random ints.
System.out.println(point[0] + "," + point[1] + "," + point[2]);
}
System.out.println();
//My current understanding is that this section should step through
//ArrayList list and retrieve each Integer[] point added above. It runs, but only
//the values of the last Integer[] point from above are displayed 10 times.
Iterator it = list.iterator();
while (it.hasNext()) {
point = (Integer[])it.next();
for (int i = 0; i < 3; i++) {
System.out.print(point[i] + ",");
}
System.out.println();
}
}
}
First of all, several of the other answers are misleading and/or incorrect. Note that an array is an object. So you can use them as elements in a list, no matter whether the arrays themselves contain primitive types or object references.
Next, declaring a variable as List<int[]> list is preferred over declaring it as ArrayList<int[]>. This allows you to easily change the List to a LinkedList or some other implementation without breaking the rest of your code because it is guaranteed to use only methods available in the List interface. For more information, you should research "programming to the interface."
Now to answer your real question, which was only added as a comment. Let's look at a few lines of your code:
Integer[] point = new Integer[3];
This line creates an array of Integers, obviously.
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 3; j++) {
point[j] = (int)(Math.random() * 10);
}
//Doesn't this line add filled Integer[] point to the
//end of ArrayList list?
list.add(point);
//...
}
Here you assign values to the elements of the array and then add a reference to the array to your List. Each time the loop iterates, you assign new values to the same array and add another reference to the same array to the List. This means that the List has 10 references to the same array which has been repeatedly written over.
Iterator it = list.iterator();
while (it.hasNext()) {
point = (Integer[])it.next();
for (int i = 0; i < 3; i++) {
System.out.print(point[i] + ",");
}
System.out.println();
}
}
Now this loop prints out the same array 10 times. The values in the array are the last ones set at the end of the previous loop.
To fix the problem, you simply need to be sure to create 10 different arrays.
One last issue: If you declare it as Iterator<Integer[]> it (or Iterator<int[]> it), you do not need to cast the return value of it.next(). In fact this is preferred because it is type-safe.
Finally, I want to ask what the ints in each array represent? You might want to revisit your program design and create a class that holds these three ints, either as an array or as three member variables.
I would highly recommend to enclose the integer array of 3 numbers into a meaningful class, that would hold, display and control an array of 3 integers.
Then in your main, you can have an growing ArrayList of objects of that class.
You have an extra ) here:
element = (int[])it.next()); //with the extra parenthesis the code will not compile
should be:
element = (int[])it.next();
Besides the problem in the other answer, you cal it.next() two times, that cause the iterator move forward two times, obviously that's not what you want. The code like this:
element = (int[])it.next());
String el = (String)element;
But actually, I don't see you used el. Although it's legal, it seems meaningless.

Categories