2D Arrays
A theater ticket doesn't just say "seat 7." It says "row C, seat 7," because a theater has two directions.
The Arrays you've built so far are a single line of slots, like one row of eggs. That works for a list of scores. But plenty of data comes in a grid:
- a gradebook, with one row per student and one column per quiz
- a seating chart, with rows and seats
- a tic-tac-toe or chess board
- a weekly timetable, with days and class periods
For grids, Java has two-dimensional arrays, usually called 2D arrays.
Rows and seats
In a theater, every seat has two numbers: which row it's in, and which seat it is in that row. "Row 2, seat 5" pinpoints exactly one chair. You always give the row first, then the seat.
A 2D array works the same way. Every item has two indexes: the row first, then the column. And like every array in Java, both start counting from 0.
Creating a 2D array
With values you already know, nest one set of curly braces inside another. Each inner set is one row:
int[][] grades = {
{88, 92, 79}, // row 0: Maria's three quizzes
{75, 68, 81}, // row 1: Ben's
{95, 90, 98} // row 2: Carlo's
};The type int[][], with two pairs of brackets, means "an array of arrays of ints." That's exactly what it is: an outer array whose items are rows, and each row is an ordinary array.
Laid out as a table, it looks like this:
col 0 col 1 col 2
row 0: 88 92 79
row 1: 75 68 81
row 2: 95 90 98When you know the size but not the values yet, use new with the number of rows and the number of columns:
int[][] seats = new int[4][6]; // 4 rows, 6 columns, all starting at 0Reading and changing a cell
Give the row index, then the column index, each in its own brackets:
int[][] grades = {
{88, 92, 79},
{75, 68, 81},
{95, 90, 98}
};
System.out.println(grades[1][2]); // 81: row 1 (Ben), column 2 (quiz 3)
grades[1][1] = 72; // Ben's quiz 2 regraded
System.out.println(grades[1][1]); // 72A good way to remember the order: row, then column, the same order you read a page. First you find the line, then you move across it.
How big is it?
Because a 2D array is an array of rows:
grades.lengthis the number of rows (3).grades[0].lengthis the number of columns in row 0 (3).
int[][] seats = new int[4][6];
System.out.println(seats.length); // 4 rows
System.out.println(seats[0].length); // 6 columnsLooping through every cell
Here's where Nested Loops pay off. The outer loop walks through the rows, and the inner loop walks across the columns of the current row:
int[][] grades = {
{88, 92, 79},
{75, 68, 81},
{95, 90, 98}
};
for (int row = 0; row < grades.length; row++) {
for (int col = 0; col < grades[row].length; col++) {
System.out.print(grades[row][col] + " ");
}
System.out.println();
}88 92 79
75 68 81
95 90 98Notice the inner loop's condition: col < grades[row].length. It asks the current row how long it is. That's the safest habit, and the next section shows why.
The for-each loop works too, and reads nicely when you don't need the indexes. Each row is an ordinary int[]:
int total = 0;
for (int[] row : grades) {
for (int grade : row) {
total += grade;
}
}
System.out.println(total); // 766Row totals and column totals
Two very common jobs have slightly different shapes.
One row at a time, like each student's average, uses the loops in their usual order. Reset the total at the start of each row:
for (int row = 0; row < grades.length; row++) {
int sum = 0;
for (int col = 0; col < grades[row].length; col++) {
sum += grades[row][col];
}
System.out.println("Row " + row + " total: " + sum);
}One column at a time, like the class average on each quiz, flips the loops: the outer loop picks a column, and the inner loop goes down through the rows:
for (int col = 0; col < grades[0].length; col++) {
int sum = 0;
for (int row = 0; row < grades.length; row++) {
sum += grades[row][col];
}
System.out.println("Quiz " + (col + 1) + " total: " + sum);
}Rows can have different lengths
Since each row is its own array, rows don't have to be the same length. This is called a jagged array:
int[][] clubScores = {
{10, 8},
{9, 7, 10, 6},
{8}
};Maybe one club met twice, another four times, and another once. Loops that use grades[row].length handle this perfectly, which is why that's the habit to build. A loop that assumed every row had grades[0].length columns would crash on row 2 here, or skip items in row 1.
Printing a 2D array quickly
Arrays.toString shows the directions to each row, not the values. For 2D arrays, use Arrays.deepToString:
int[][] small = {{1, 2}, {3, 4}};
System.out.println(Arrays.deepToString(small)); // [[1, 2], [3, 4]]It's handy for a quick look while debugging. For anything a user will see, loop and format the output yourself.
Try it
This program stores a small class's quiz grades in a 2D array, prints a formatted gradebook with each student's average, and finds the class average for each quiz. Predict the table.
Running Java here
Running Java right in the browser is coming to Syntaxia soon. On your own computer, save this program as Main.java and run it with java Main.java, or use your editor's Run button.
Check your prediction
Name Q1 Q2 Q3 Average
Maria 88 92 79 86.3
Ben 75 68 81 74.7
Carlo 95 90 98 94.3
Quiz avg 86.0 83.3 86.0Each student's row is added across, then divided by the number of quizzes. The last line flips the loops to add down each column instead, then divides by the number of students.
Try it yourself
- Add a fourth student,
Dina, with grades 82, 85, and 88. What do you need to change? (Two places.) - Add a fourth quiz column for every student. Does the table still line up? What else needs updating?
- Find the single highest grade in the whole array, and print which student got it and on which quiz.
Check your understanding
Up next
Arrays have one big limitation: their size is fixed forever. When a new student joins, the carton is full. Next, you'll meet a list that grows and shrinks as you need it: ArrayList.
