Fancy (Integer-Array) Indexing
Pick any positions, in any order, with a list or array of indexes — including rows, columns and (row, col) pairs.
Slices only give regular patterns (a range, every k-th). What if you want Virat's scores in matches 1, 4 and 7 — or the top 3 scores in sorted order — or the players in a custom order? You pass a list of positions. NumPy calls this fancy indexing.
Definition
Fancy indexing (also called integer-array indexing) is selecting elements by passing a list or array of integer indexes inside the brackets, e.g.
arr[[0, 3, 6]]. NumPy returns a new array (a copy) whose shape follows the shape of the index array, with the elements in exactly the order you listed — repeats allowed.
- List of indexes — note the double brackets: the outer
[]is indexing, the inner[0, 3, 6]is the list of positions. - Any order, repeats allowed —
arr[[6, 0, 0]]is fine. - Shape follows the index array — a 2×2 index array gives a 2×2 result.
- Copy — like boolean indexing (and unlike slicing), the result does not share memory with
arr.
Syntax
python
arr[[i1, i2, i3]] # 1D: pick these positions
arr2d[[r1, r2]] # 2D: pick whole rows
arr2d[:, [c1, c2]] # 2D: pick whole columns
arr2d[[r1, r2], [c1, c2]] # 2D: pick PAIRS (r1,c1) and (r2,c2)
arr2d[np.ix_([r1, r2], [c1, c2])] # 2D: rows x columns grid (sub-table)| Form | What is selected | Result shape (from (3, 8)) |
|---|---|---|
arr[[0, 2]] | rows 0 and 2 | (2, 8) |
arr[:, [0, 3]] | columns 0 and 3 | (3, 2) |
arr[[0, 2], [1, 5]] | cells (0,1) and (2,5) — paired | (2,) |
arr[np.ix_([0, 2], [1, 5])] | rows {0,2} × columns {1,5} | (2, 2) |
Example — 1D: chosen matches, custom order
python
import numpy as np
virat_runs = np.array([72, 45, 88, 31, 64, 0, 103, 52, 19, 77, 41, 93, 28, 66])
print("Matches 1, 4, 7 :", virat_runs[[0, 3, 6]])
print("Last, first, middle :", virat_runs[[-1, 0, 7]])
print("Repeats allowed :", virat_runs[[6, 6, 0]])
idx = np.array([[0, 1], [12, 13]])
print("Shape follows index array:")
print(virat_runs[idx])text
Matches 1, 4, 7 : [ 72 31 103]
Last, first, middle : [66 72 52]
Repeats allowed : [103 103 72]
Shape follows index array:
[[72 45]
[28 66]]How it works: each number in the index list is looked up one by one, and the results are placed in the same order (and the same shape) as the index list.
Example — top 3 scores with argsort
python
virat_runs = np.array([72, 45, 88, 31, 64, 0, 103, 52, 19, 77, 41, 93, 28, 66])
order = np.argsort(virat_runs) # indexes that would sort the array
top3_idx = order[::-1][:3] # largest first, take 3
print("Top-3 indexes :", top3_idx)
print("Top-3 scores :", virat_runs[top3_idx])
print("Match numbers :", top3_idx + 1)text
Top-3 indexes : [ 6 11 2]
Top-3 scores : [103 93 88]
Match numbers : [ 7 12 3]How it works: np.argsort returns positions, not values. Feeding those positions back in with fancy indexing reorders the data. This "argsort + fancy index" pattern is how you rank players, sort rows by a column, etc.
Example — 2D: rows, columns, pairs and grids
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("Rows 2 and 0 (Hardik, Virat):")
print(scores[[2, 0]])
print("Matches 1 and 8 for everyone:")
print(scores[:, [0, 7]])
print("Pairs (0,6) and (1,3):", scores[[0, 1], [6, 3]])
print("Grid rows {0,1} x cols {0,7}:")
print(scores[np.ix_([0, 1], [0, 7])])text
Rows 2 and 0 (Hardik, Virat):
[[ 45 32 0 67 18 54 78 22]
[ 72 45 88 31 64 0 103 52]]
Matches 1 and 8 for everyone:
[[72 52]
[56 17]
[45 22]]
Pairs (0,6) and (1,3): [103 88]
Grid rows {0,1} x cols {0,7}:
[[72 52]
[56 17]]How it works: with two index lists, NumPy pairs them up position by position: [0, 1] with [6, 3] means cells (0, 6) and (1, 3) → Virat's 103 and Rohit's 88. If you want every combination (a sub-table), use np.ix_ — or do it in two steps: scores[[0, 1]][:, [0, 7]].
Comparison — the three ways to select
Slicing a[1:4] | Boolean a[a > 50] | Fancy a[[0, 3, 6]] | |
|---|---|---|---|
| Selects by | a regular range | a condition | a list of positions |
| Order / repeats | fixed order, no repeats | original order | any order, repeats OK |
| Returns | view | copy | copy |
| Result shape | same ndim as input | always 1D (full mask) | shape of the index array |
Common mistakes
- ❌
virat_runs[0, 3, 6](single brackets) — that means "axis 0 = 0, axis 1 = 3, axis 2 = 6" →IndexError: too many indices. ✅virat_runs[[0, 3, 6]]. - ❌
scores[[0, 1], [0, 7]]expecting a 2×2 block. ✅ That returns 2 paired cells. Usescores[np.ix_([0, 1], [0, 7])]. - ❌ Two index lists of different lengths, e.g.
scores[[0, 1, 2], [0, 1]]→IndexError: shape mismatch. - ❌ Editing a fancy-indexed result and expecting the original to change. ✅ It's a copy; assign directly instead:
scores[[0, 2], 0] = 0.
Interview tip
Q: What does arr[[1, 2], [3, 4]] return for a 2D array?
A: Two elements: arr[1, 3] and arr[2, 4]. The two index arrays are broadcast together and paired element-wise; to get the 2×2 grid of rows {1, 2} and columns {3, 4}, use arr[np.ix_([1, 2], [3, 4])].
Key points to remember
- Fancy indexing passes a list/array of integer positions: arr[[0, 3, 6]] (note the double brackets).
- Elements come back in the order you list them; repeats are allowed.
- The result's shape follows the shape of the index array.
- Fancy indexing always returns a COPY (slicing returns a view).
- In 2D, arr[[r1, r2]] picks rows, arr[:, [c1, c2]] picks columns.
- arr[[r1, r2], [c1, c2]] picks PAIRED cells (r1,c1), (r2,c2); use np.ix_ for a rows × columns grid.
- np.argsort + fancy indexing is the standard way to sort or rank data.
Try it yourself
Pick matches in any order
Rows, columns, pairs and np.ix_
Practice: rank the players
Revision Flashcards
Tap a card to flip it and see the answer.
