Blog Post #55: A List of Lists: Getting Started with 2D Lists (Matrices)

In our previous post on copying lists (Post #54), we briefly mentioned the idea of “nested lists.” This simple concept—putting lists inside other lists—unlocks the ability to represent complex, grid-like data structures.

In this post, we will explore 2D lists (also known as matrices). You’ll learn how to structure them to represent tabular data and how to access and modify elements using double-bracket notation.

From a Line to a Grid

A standard list is one-dimensional, like a single row of items. But much of the data we encounter in the real world has two dimensions: rows and columns. Think of a spreadsheet, a chessboard, a tic-tac-toe board, or a pixel grid in an image.

To model this in Python, we can create a list where each item is another list. The outer list holds the rows, and each inner list holds the data for the columns in that row.

Creating a 2D List

Let’s represent a simple 3×3 tic-tac-toe board. We’ll create a list that contains three other lists. It’s conventional to write this on multiple lines to visually represent the grid structure.

# A list containing three inner lists (the rows)
tic_tac_toe_board = [
    ["X", "O", "X"],  # Row 0
    ["O", "X", "O"],  # Row 1
    ["X", "O", "O"]   # Row 2
]

In this structure, tic_tac_toe_board is a list with 3 elements. Each of those elements is, in turn, another list containing 3 string elements.

Accessing Elements with Double Brackets

To access an element in a 2D list, you need to provide two indexes: the first for the row and the second for the column. This is done with a double set of square brackets: my_list[row_index][column_index].

Let’s break down how this works:

  1. The first index, [row_index], selects one of the inner lists.
  2. The second index, [column_index], then selects an item from within that chosen inner list.

Using our tic-tac-toe board, let’s get the item in the center.

# Get the item at row 0, column 1 (the top-middle 'O')
# Remember that indexing starts at 0!
item = tic_tac_toe_board[0][1]
print(f"The item at row 0, column 1 is: '{item}'")

# Get the center item (row 1, column 1)
center_item = tic_tac_toe_board[1][1]
print(f"The center item is: '{center_item}'")

The output will be:

The item at row 0, column 1 is: 'O'
The center item is: 'X'

Modifying Elements in a 2D List

Because lists are mutable (as we learned in Post #49), we can also use this double-bracket notation to change any element in our grid. Let’s say we want to change the bottom-right corner of our board from “O” to “X”.

print(f"The bottom row before the change is: {tic_tac_toe_board[2]}")

# Change the item at row 2, column 2
tic_tac_toe_board[2][2] = "X"

print(f"The bottom row after the change is: {tic_tac_toe_board[2]}")

The output shows the in-place modification:

The bottom row before the change is: ['X', 'O', 'O']
The bottom row after the change is: ['X', 'O', 'X']

What’s Next?

You now know how to create and manage 2D lists to represent grid-like data. By using a “list of lists” and double-bracket notation ([row][col]), you can access and modify any cell in your grid, opening the door to creating simple games, processing tabular data, and more.

Now that we can build more complex data structures, how do we loop through them? And even in a simple 1D list, how can we get both the index and the value at the same time while looping? In Post #56, we will learn a professional and “Pythonic” way to loop with the enumerate() function.

Author

Debjeet Bhowmik

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com

Leave a Comment