Free for students · Ad-free · WCAG 2.1 AA Compliant · Accessibility

2D Array Traversals

Lesson ~11 min read 8 MCQs

In simple terms: In simple terms, 2D array traversal is about using nested loops to visit every item in a grid of data, either row-by-row or column-by-column, to perform some task.

Why this matters

Imagine you're in charge of the seating chart for your school's production of Hamilton. You have a 2D array representing the theater: each row is a row of seats, and each "column" in that row is a specific seat. Now, imagine the director wants to place a flyer on every single seat. How would you do it systematically?

You wouldn't just run around randomly. You'd probably start with the first row, walk across, and place a flyer on each seat. Then you'd move to the second row and do the same, and so on, until you've covered the entire theater. This methodical, row-by-row process is exactly what we call "traversal." In this lesson, we'll learn how to write code that walks through 2D arrays just like that, and we'll even see how to walk through them column by column.

Concept overview

flowchart TD
    A[Start] --> B{Initialize row i = 0};
    B --> C{i < num_rows?};
    C -- Yes --> D{Initialize col j = 0};
    C -- No --> K[End];
    D --> E{j < num_cols?};
    E -- Yes --> F[Process element grid[i][j]];
    F --> G{j = j + 1};
    G --> E;
    E -- No --> H{i = i + 1};
    H --> C;
A flowchart illustrating row-major traversal of a 2D array. It shows an outer loop for rows (i) and a nested inner loop for columns (j), with a process block for accessing each element at grid[i][j].

Core explanation

Alright, let's dive into how we can programmatically walk through our 2D arrays.

The Big Idea: An Array of Arrays

First, let's solidify our mental model. A 2D array in Java is really an array of arrays.

Think of a parking garage. The entire garage is your 2D array. Each level of the garage is a single 1D array. And each parking spot on a level is an element.

// A 3x4 parking garage (3 levels, 4 spots per level)



<figure class="lesson-figure"><div class="shr-widget" data-shr-widget="{&quot;type&quot;:&quot;array_animation&quot;,&quot;label&quot;:&quot;Parking Garage Grid&quot;,&quot;values&quot;:[101,102,103,104,201,202,203,204,301,302,303,304],&quot;highlight&quot;:[0]}" aria-label="A 3x4 grid showing indices for rows 0-2 and columns 0-3."></div><figcaption class="lesson-figure-caption">A 2D array visualized as a grid of rows and columns.</figcaption></figure>



int[][] parkingGarage = {
  {101, 102, 103, 104}, // Level 1 (a 1D array)
  {201, 202, 203, 204}, // Level 2 (a 1D array)
  {301, 302, 303, 304}  // Level 3 (a 1D array)
};

To get to a specific spot, you need two pieces of information: the level (row) and the spot number (column). parkingGarage[1][2] would get you to spot 203 (remember, we start counting from 0!).

Row-Major Traversal: The Standard Walkthrough

Row-major traversal is the most common and intuitive way to visit every element. It's just like reading a book: you go left-to-right across the first line, then move to the second line, and so on.

To do this, we use nested for loops.

  • The outer loop handles the rows. It iterates from row 0 to the last row.
  • The inner loop handles the columns. For each row, it iterates from column 0 to the last column in that row.
int[][] scores = {
    {88, 92, 78},
    {95, 89, 91},
    {76, 81, 85},
    {99, 94, 90}
};

// Row-major traversal to print all scores



<figure class="lesson-figure"><div class="shr-widget" data-shr-widget="{&quot;code&quot;:[&quot;for (int i = 0; i &lt; 4; i++)&quot;,&quot;  for (int j = 0; j &lt; 3; j++)&quot;,&quot;    print(scores[i][j]);&quot;],&quot;type&quot;:&quot;for_loop_trace&quot;,&quot;array&quot;:[88,92,78,95,89,91],&quot;trace_steps&quot;:[{&quot;line&quot;:1,&quot;vars&quot;:{&quot;i&quot;:0,&quot;j&quot;:0}},{&quot;line&quot;:2,&quot;vars&quot;:{&quot;i&quot;:0,&quot;j&quot;:0},&quot;highlight_cell&quot;:0},{&quot;line&quot;:2,&quot;vars&quot;:{&quot;i&quot;:0,&quot;j&quot;:1},&quot;highlight_cell&quot;:1},{&quot;line&quot;:2,&quot;vars&quot;:{&quot;i&quot;:0,&quot;j&quot;:2},&quot;highlight_cell&quot;:2},{&quot;line&quot;:1,&quot;vars&quot;:{&quot;i&quot;:1,&quot;j&quot;:0},&quot;highlight_cell&quot;:3}]}" aria-label="Animation showing i and j indices moving through a 2D array."></div><figcaption class="lesson-figure-caption">Tracing the nested loops for row-major order.</figcaption></figure>



for (int i = 0; i < scores.length; i++) { // Outer loop for rows
    for (int j = 0; j < scores[i].length; j++) { // Inner loop for columns
        System.out.print(scores[i][j] + " ");
    }
    System.out.println(); // New line after each row
}

Let's break down those loop conditions:

  • scores.length: This gives you the number of rows (in this case, 4). It's the "height" of the 2D array.
  • scores[i].length: This gives you the number of columns in the current row i. It's the "width" of that specific row. For the AP exam, you can usually assume all rows have the same length, so scores[0].length would also work.

Column-Major Traversal: Walking Down the Aisles

Sometimes, you need to process the data column by column. Imagine you wanted to find the average score for the first quiz, then the second, then the third. You'd need to go down the columns.

This is called column-major traversal. To achieve this, we flip the logic of our loops.

  • The outer loop now handles the columns.
  • The inner loop now handles the rows.
// Column-major traversal to print all scores
// Assume a rectangular array (all rows have same length)
int numCols = scores[0].length;
int numRows = scores.length;

for (int j = 0; j < numCols; j++) { // Outer loop for columns
    for (int i = 0; i < numRows; i++) { // Inner loop for rows
        // The access order is STILL [row][col] or [i][j]!
        System.out.print(scores[i][j] + " ");
    }
    System.out.println(); // New line after each column is processed
}

The output would look different: 88 95 76 99 92 89 81 94 78 91 85 90

The most common mistake here is to try to access the element as scores[j][i]. Don't do that! The physical structure of the array is still [row][col]. We are just changing the order in which we visit the elements. Think of it this way: i is always your row index, and j is always your column index. We just put the j loop on the outside to prioritize columns.

Using the Enhanced For Loop

You can also traverse a 2D array with nested enhanced for loops. This can be cleaner, but it has two important characteristics:

  1. It is always row-major.
  2. It is "read-only"—you can't use it to change the values in the array.

Here’s the structure:

// Enhanced for loop traversal (always row-major)
for (int[] row : scores) { // Outer loop: get each 1D array (row)
    for (int score : row) { // Inner loop: get each int from the row
        System.out.print(score + " ");
    }
    System.out.println();
}

Look closely at the data types.

  • The outer loop variable, row, must be of type int[], because scores is an array of int arrays. Each time the outer loop runs, row holds one of the inner arrays (e.g., {88, 92, 78}).
  • The inner loop variable, score, is of type int, because it's iterating through the elements of the int[] named row.

A critical warning: You cannot modify the array this way. Consider this code:

for (int[] row : scores) {
    for (int score : row) {
        score = 0; // This does NOT change the array!
    }
}

This code does not fill the scores array with zeros. The variable score is a copy of the value from the array. Changing the copy doesn't affect the original. If you need to modify the array's contents, you must use a standard indexed for loop.

Common confusion between row-major and column-major loop order.

See it in action

Code

    
Memory
Variables
Step 0 / 0

Worked examples

Let's put these concepts into practice with a few common scenarios.

Example 1

Calculating the Average of All Grades

Problem: You are given a 2D array of student grades. Write a method to calculate the average of all the grades in the array.

Data:

double[][] grades = {
    {85.5, 92.0, 76.8},
    {99.0, 88.5, 91.2}
};

Solution Walkthrough:

  1. 1
    Goal
    We need to visit every single grade, add it to a running total, and keep track of how many grades we've seen.
  2. 2
    Strategy
    A row-major traversal is perfect for this. We'll use nested for loops to visit each element. We need a double variable for the sum and an int for the count.
  3. 3
    Implementation
    public double calculateAverage(double[][] grades) {
        double sum = 0.0;
        int count = 0;
    
        for (int i = 0; i < grades.length; i++) {
            for (int j = 0; j < grades[i].length; j++) {
                sum += grades[i][j]; // Add the current grade to the sum
                count++;             // Increment the count of grades
            }
        }
    
        // Avoid division by zero if the array is empty!
        if (count == 0) {
            return 0.0;
        }
    
        return sum / count;
    }
  4. 4
    Why it works
    The outer loop (i) iterates through the rows (0 then 1). For each row, the inner loop (j) iterates through the columns (0, 1, then 2). The expression grades[i][j] correctly accesses each element one by one (85.5, 92.0, 76.8, then 99.0, etc.), adding it to sum. Finally, dividing the total sum by the total count gives us the average.
Example 2

Finding the Maximum Value in Each Column

Problem: You have a 2D array representing daily sales for different stores in Dallas. Find the highest sales figure for each day (i.e., for each column).

Data:

int[][] sales = {
    {1200, 1500, 1350}, // Store 1
    {1100, 1800, 1400}, // Store 2
    {1450, 1480, 1600}  // Store 3
};

Solution Walkthrough:

  1. 1
    Goal
    We need to process the data column by column. For column 0, we find the max. For column 1, we find the max, and so on.
  2. 2
    Strategy
    This screams for column-major traversal. The outer loop will iterate through columns, and for each column, the inner loop will scan down the rows to find the maximum value in that column.
  3. 3
    Implementation
    public void findMaxInEachColumn(int[][] data) {
        if (data.length == 0) return; // Handle empty array
    
        int numCols = data[0].length;
        int numRows = data.length;
    
        for (int j = 0; j < numCols; j++) { // Outer loop for columns
            int maxInCol = data[0][j]; // Initialize max with the first element of the column
    
            for (int i = 1; i < numRows; i++) { // Inner loop for rows (start at 1)
                if (data[i][j] > maxInCol) {
                    maxInCol = data[i][j];
                }
            }
            System.out.println("Max for column " + j + " is: " + maxInCol);
        }
    }
  4. 4
    Why it works
    The outer loop (j) selects a column. We initialize maxInCol to the first element in that column (data[0][j]). Then, the inner loop (i) scans down the rest of that same column (data[1][j], data[2][j], etc.), updating maxInCol whenever a larger value is found. After the inner loop finishes, we have the max for that one column and print it before the outer loop moves to the next column.
Handling empty arrays to prevent errors.

Try it yourself

Ready to try a couple on your own? Don't worry about writing a full class, just focus on the method logic.

Problem 1: Find the Maximum Value Write a method findMax that takes a 2D array of integers and returns the single largest value in the entire array.

  • Hint: You'll need a variable, maybe called currentMax, to keep track of the largest value you've seen so far. What should you initialize it to? Think about what would happen if all the numbers in the array were negative. A safe bet is to initialize it to the very first element, grid[0][0].

Problem 2: "Flatten" the Array Write a method flatten that takes a 2D array of integers (int[][]) and returns a new 1D array (int[]) containing all the elements from the 2D array, read in row-major order.

  • Hint: First, figure out the total number of elements to determine the size of the new 1D array you need to create. You'll also need a separate counter variable to keep track of the current position in your new 1D array as you fill it.
Visualizing the flattening process from 2D to 1D.