2D Indexing: a[row, col]
Read single cells and whole rows of a 2D array with arr[row, col], and see why arr[row][col] is not the same thing.
Now the data is a table: 3 players (rows) × 8 matches (columns). To answer "What did Rohit score in match 3?" you need two positions — which row (player) and which column (match).
text
match: 0 1 2 3 4 5 6 7
row 0 Virat [ 72, 45, 88, 31, 64, 0, 103, 52 ]
row 1 Rohit [ 56, 0, 74, 88, 32, 45, 61, 17 ]
row 2 Hardik [ 45, 32, 0, 67, 18, 54, 78, 22 ]
axis 1 (columns) ─────────────────────────►
axis 0 (rows) ▼Definition
2D indexing selects an element of a 2D array by giving one index per axis, separated by a comma inside one pair of square brackets:
arr[row, col]. The first index chooses the row (axis 0), the second chooses the column (axis 1).
- One index per axis — a 2D array has 2 axes, so a full address needs 2 numbers. Give both and you get a single scalar.
- Axis 0 = rows (here: players), axis 1 = columns (here: matches).
scores.shapeis(3, 8)→ 3 rows, 8 columns. - Fewer indexes than axes —
arr[1]gives only the row index, so NumPy returns the whole row as a 1D array. - Negative indexes work on every axis:
arr[-1, -1]is the bottom-right cell.
Syntax
python
arr[r, c] # single element at row r, column c -> scalar
arr[r] # whole row r -> 1D array (same as arr[r, :])
arr[-1, -1] # last row, last column| Part | Meaning | Valid range for shape (3, 8) |
|---|---|---|
r | row position along axis 0 | 0…2 or -3…-1 |
c | column position along axis 1 | 0…7 or -8…-1 |
Example — single cells
python
import numpy as np
scores = np.array([
[72, 45, 88, 31, 64, 0, 103, 52], # row 0: Virat
[56, 0, 74, 88, 32, 45, 61, 17], # row 1: Rohit
[45, 32, 0, 67, 18, 54, 78, 22], # row 2: Hardik
])
print("shape:", scores.shape)
print("Virat, match 1 :", scores[0, 0])
print("Rohit, match 3 :", scores[1, 2])
print("Hardik, last :", scores[2, -1])
print("Bottom-right :", scores[-1, -1])text
shape: (3, 8)
Virat, match 1 : 72
Rohit, match 3 : 74
Hardik, last : 22
Bottom-right : 22How it works: scores[1, 2] → row 1 (Rohit), column 2 (match 3) → 74. Each comma-separated number fixes one axis.
Example — a whole row with one index
python
scores = np.array([
[72, 45, 88, 31, 64, 0, 103, 52], # row 0: Virat
[56, 0, 74, 88, 32, 45, 61, 17], # row 1: Rohit
[45, 32, 0, 67, 18, 54, 78, 22], # row 2: Hardik
])
rohit = scores[1]
print(rohit)
print("shape:", rohit.shape, " ndim:", rohit.ndim)
print("Rohit's total:", rohit.sum())text
[56 0 74 88 32 45 61 17]
shape: (8,) ndim: 1
Rohit's total: 373How it works: with only the row index, NumPy fills the missing axis with "everything" (:). scores[1] is the same as scores[1, :]. An integer index removes that axis, so the 2D array becomes 1D with shape (8,).
a[row, col] vs a[row][col]
With a nested Python list you must write lst[1][2]. NumPy also accepts arr[1][2], and for a single element the answer is the same — but it works differently and it breaks with slices.
python
scores = np.array([
[72, 45, 88, 31, 64, 0, 103, 52], # row 0: Virat
[56, 0, 74, 88, 32, 45, 61, 17], # row 1: Rohit
[45, 32, 0, 67, 18, 54, 78, 22], # row 2: Hardik
])
print("scores[1, 2] =", scores[1, 2])
print("scores[1][2] =", scores[1][2])
# The difference appears with slices:
print("scores[:, 0] =", scores[:, 0]) # column 0 -> first match of every player
print("scores[:][0] =", scores[:][0]) # NOT column 0! -> row 0text
scores[1, 2] = 74
scores[1][2] = 74
scores[:, 0] = [72 56 45]
scores[:][0] = [ 72 45 88 31 64 0 103 52]How it works:
arr[1, 2] | arr[1][2] | |
|---|---|---|
| Steps | one indexing operation with a tuple (1, 2) | two operations: arr[1] makes a temporary row, then [2] indexes it |
| Speed | faster | slower (creates an intermediate array) |
| With slices | arr[:, 0] = column 0 ✅ | arr[:][0] = (arr[:])[0] = row 0 ❌ |
| Assignment | always safe | works for plain indexes, but confusing with fancy/boolean indexes |
scores[:] is "all rows" — the whole array — and then [0] takes its first row. So arr[:][0] is not a column. Always use the comma form in NumPy.
Python list vs NumPy (2D)
| Task | Nested Python list | NumPy 2D array |
|---|---|---|
| One cell | lst[1][2] | arr[1, 2] |
| One row | lst[1] | arr[1] or arr[1, :] |
| One column | [row[0] for row in lst] (loop) | arr[:, 0] (no loop) |
| Shape check | manual len(lst), len(lst[0]) | arr.shape |
Common mistakes
- ❌
scores[2, 8]for Hardik's 8th match. ✅ Columns are 0–7, so it'sscores[2, 7]orscores[2, -1]— otherwiseIndexError: index 8 is out of bounds for axis 1 with size 8. - ❌
scores[:][0]to get the first column. ✅scores[:, 0]. - ❌ Mixing up row and column order (
scores[match, player]). ✅ Order follows the shape(3, 8)→[player, match]. - ❌
scores[1, 2, 0]on a 2D array. ✅ A 2D array accepts at most 2 indexes →IndexError: too many indices for array.
Interview tip
Q: Why prefer arr[i, j] over arr[i][j] in NumPy?
A: arr[i, j] is a single indexing call with a tuple, so it is faster and works with slices on any axis (arr[:, j] is column j). arr[i][j] indexes twice; with slices it becomes (arr[:])[j], which selects a row, not a column.
Key points to remember
- A 2D array needs one index per axis: arr[row, col] inside ONE pair of brackets.
- Axis 0 = rows, axis 1 = columns; the order follows arr.shape, e.g. (3, 8) = [player, match].
- arr[r] alone returns the whole row r as a 1D array (same as arr[r, :]).
- Giving an integer for an axis removes that axis from the result; two integers on a 2D array give a scalar.
- arr[r][c] gives the same single value but indexes twice (slower) and breaks with slices: arr[:][0] is row 0, not column 0.
- Negative indexes work on every axis: arr[-1, -1] is the bottom-right element.
Try it yourself
Cells and rows of the scores table
arr[row, col] vs arr[row][col]
Practice: compare two players in one match
Revision Flashcards
Tap a card to flip it and see the answer.
