2D Arrays
The goal of this lab period is to practice using 2D arrays in Java. Unlike last week and unlike in most of the other labs you will do this semester, you are not building a Grid class that you will use to store data in your project. This lab is designed to be practice with 2-D arrays that will prepare you for the work in the project, but won't be used directly. You do need to do it to get credit for the lab checkpoint!
Tasks
- Setup
Create a working directory for today's project (p2/src/ to make it easy to submit to Gradescope. Load the src folder into VSCode to avoid having to do anything with packages.). Then start a Java file called Grid.java and make a public class called Grid.
Note: You will not instantiate a Grid object using this class! Do not write constructors or getters and setters.
Instead, create a main method in the Grid class. This is where you will write most of your code for this lab.
- Creating a 2-D Array
In your main method, create a 2D array of type int. In the example below, we'll call it grid. (This defines but doesn't instantiate grid).
int[][] grid;Start by allocating the 2D array in a single new statement, giving it 3 rows and 5 columns. The code for that looks like this:
grid = new int[3][5];Note that the first set of square brackets corresponds to the rows of the matrix, and the second set of square brackets corresponds to the columns.
Now let's try an alternative method of creating a 2-D array by allocating the row size and column size separately. This lets us have 3 rows with 3 different numbers of columns. The code below does this to create a 2-D array named grid2 with 3 rows and 1, 2 and 3 columns for rows 0, 1 and 2 respectively.
int[][] grid2 = new int[3][]; for(int i = 0; i < 3; i++){ grid2[i] = new int[i+1]; }Be a little careful with this method: if you try to print outgrid2[0][0]between the instantiation ofgridand the start of the for loop, what happens?To fix the null entries of
gridorgrid2, regardless of which way you instantiated the object, you have to go through every location in the 2-D array and create an int to put in it. Do that now and give each location in both grid and grid2 a random int.+ (More Detail)
When working with 2-D arrays we often use nested for loops:
for(int i=0;i<grid.length;i++) { for(int j=0;j<grid[ i ].length;j++) { /* access the elements of the array using i and j as index variables */ } }This example iterates over all of the elements in the
gridyou created above. You will need to generalize this forgrid2or other 2-D arrays.Remember that you have to use different names for the nested loop variables. For almost all 2-D arrays, you want to loop over rows in the outer loop and columns in the inner loop. The reason is that most 2-D arrays are stored in row-major order in memory, so looping over rows and then columns accesses memory in linear order, which is faster than jumping around.
While you can hard-code the number of rows and columns into the for loops (e.g. 3 and 5), this way is less error prone. For the outer loop, it iterates over the number of rows which is stored in
grid.length. For the inner loop, it iterates over the number of columns in row i which is stored ingrid[ i ].lengthWhen creating a 2-D array, you have to first allocate the 2-D grid of int references (you already did this), then use a nested loop, as above, to allocate each int element grid[i][j] individually. Assign to each grid[i][j] a new int by sampling a random number. To break this down into 2 smaller steps, you can start by setting all of the values to 4 to verify that your code working. Then you can replace 4 with a randomly generated integer (see lab 1, step 6, details for how to do this if you forgot).
- Print the Contents of the 2-D Array
If you try to print out
grid, what happens? Presumably, you'll get something likeint@somegarbage. Unfortunately, Java Arrays don't natively implement a 'pretty' toString, so you have to loop through Arrays yourself to print things out nicely. As a follow-up, if you try to print outgrid[0][0], what gets printed out?Print out the contents of the 2D array as a 2D grid using a nested for loop. Make it look nice (i.e. we don't care how you format the output as long as you and we can tell what the output means).
+ (More Detail)
The function
System.out.printdoes not put a newline character after the string to print. The functionSystem.out.println()does put a newline character. When printing the contents of a 2-D array, it's nice to keep all the elements of a row on the same line and to add a newline between rows.For example,
gridcould look like this:1 2 7 8 9 3 4 6 1 2 2 4 7 6 0
If you want control over how Java formats numbers, especially floating point numers, look at
System.out.printfand look up printf formatting codes. - Checking if two matrices are equal
Add the following code to your main method:
int[][] arr1 = new int[2][2]; int[][] arr2 = new int[2][2]; int[][] arr3; for(int i = 0; i < 2; i++){ for(int j = 0; j < 2; j++){ arr1[i][j] = i+j; arr2[i][j] = i+j; } } arr3 = arr1;This code generates 3 new 2-D arrays,
arr1,arr2andarr3, all of which contain the same values. This will allow you to explore what it means for 2 2-D arrays to be equal in Java.Add code below the block you just pasted in that checks, using the
All of these arrays have the same values, but Java says that the first two are not equal. This is because the==operator, if (1)arr1is equal toarr2, and (2)arr1is equal toarr3. Your code should print the results of these checks. What do you expect the output to be? And what does it print?==operator tests memory location rather than if the two objects contain the same values. Sincearr3was instantiated by referencingarr1's literal reference,arr1 == arr3according to Java.Your next task is to write a new method named
gridEqualsthat checks whether 2 arrays contain identical values (in the same locations). YourgridEqualsmethod should return a bool. This method should be written so thatgridEquals(arr1, arr3)returnstrue. It should also be written so thatgridEquals( arr1, grid )should returnfalse(here,gridis the original random 2-D array of numbers you created). Write both of these statements out as code tests and determine that your method passes them. YourgridEqualsmethod should have the following declaration:public static boolean gridEquals(int[][] arr1, int[][] arr2) - Adding Command-line Arguments
The args parameter of the main() function contains strings from the command line. You can see this by adding code to print the elements of the args array, then running your Grid class a few different times with additional strings on the command line. For example, try both of the following ways of running Grid from the command line (after compiling Grid.java) and note how the output differs:
java Grid a b c djava Grid hello world command line argumentYour goal in this step is to add 2 command line arguments to your program that change its behavior. What those command line arguments do is up to you (surprise us!), but some ideas include using command line parameters to:
- Specify the size (number of rows and/or number of columns) of the grid
- Specify the range of random numbers to sample grid values within
- Create a boolean flag that dictates whether the grid entries should be positive or negative
- Pass in actual values for the grid instead of randomly generating them
At this point, your code should:
- Create 1 rectangular 2-D array and print its contents. (Rectangular means all of the rows have the same number of columns)
- Create 1 non-rectangular 2-D array and print its contents. (Each row should have a different number of columns)
- Show that your gridEquals method determines that 2 2-D arrays with identical shapes and values are equal, and 2 2-D arrays with different shapes and/or values are not equal.
- Take in 2 command line parameters that dictate some aspects of the other 3 steps (e.g. what sizes, what values), or that dictate some new aspects of your program
- Usage Statements
Many programs you will write will require command line arguments in order to work properly. To be kind to other people using your program you should always check if the user provided enough arguments and print out a usage statement if they don't. A usage statement prints out an example of how to run the program, a description of what it does, and what the arguments mean. For example, if you type
javaon the command line with no arguments, it prints out the following.Usage: java [options][args...] (to execute a class) or java [options] -jar [args...] (to execute a jar file) or java [options] -m [/ ] [args...] java [options] --module [/ ] [args...] (to execute the main class in a module) or java [options] [args] (to execute a single source-file program) ... At the top of your main function, before any of your code runs, test if the user provided at least two command line arguments. If they did not, then print out a usage statement and return. If they did, run your program as before.
Your usage statement does not need to follow the format above or be particularly complex. It should tell the user what parameters are expected and why what they supplied is not appropriate. Imagine what you would like to read when interacting with a new program that you are not familiar with.
Run Grid.java with no arguments, one argument, and with two or more arguments. It should print your usage statement in the first 2 cases, and run normally in the last case (i.e. generate and transpose the matrix).
- Creating a README File
Usage statements are one way to communicate with users about how to run your programs. README files are another. You should include both in all of your projects so that your project grader knows how to interact with your code! This is especially important for extensions, where you are making more design choices about how your program works. Without a README, we may not be able to replicate your results and give you credit for your work!
So how do you write a README file? There are lots of conventions for how to do this, but for our purposes, we will focus on 3 main things:
- Every project should include a file named README.txt in the main project folder (here, in Project2/)
- In that file, tell us in 1 to 3 sentences or bullet points which file(s) to run to replicate your important results.
- Tell us what command line arguments your program takes and how to use them
Lab checkpoint: Find me and show me your README file. Have me try to run your program (don't tell me anything not in the README). Was I able to use the command line arguments correctly to run your program? If so you've passed the checkpoint!
- Optional practice: Transposing a matrix
For the next task, create a function with the following declaration:
public static int[][] transpose(int[][] arr). This function should transpose a grid. For example, transposing the grid1 2 3 4 5 6
using your method should return1 3 5 2 4 6
This method should still work even if the grid isn't a square; however, you can and should assume the grid is rectangular (i.e. all the rows have the same length).It is highly recommended that you draw a picture for this to help you guide your code. Try starting from the example above and writing out the row and column indices for each number. You should be able to use this drawing to determine how each number moves from its position in the original grid:
gridOriginal[row][column]to its position in the transposed grid:gridTransposed[rowNew][columnNew]. More specifically, how can you definerowNewandcolumnNewin terms ofrowandcolumn? You should also use your picture to determine how the size (number of rows and columns) orgridTransposedrelates to the size ofgridOriginal.At this point, your code should create a 2-D array, print it, transpose it, then print it again. You may keep other print statements, but these print statements should be clearly highlighted in your output (in whatever way you choose).
When you are done with the lab, go ahead and get started on the current project.