ML Grind

Indexing and Slicing - NumPy Fundamentals

Implement Indexing and Slicing in Python with NumPy. medium exercise with examples, hints, and instant feedback. No setup or signup required.

Indexing and Slicing

What you'll build

A function advanced_indexing(arr) that pulls a row, a column, a sub-block, the diagonal and a row-reversed version out of a 2D array.

Background

Selecting the right slice is daily work in ML: one sample is a row of the design matrix X[i], one feature is a column X[:, j], a mini-batch is a block of rows X[start:end], and a confusion matrix's correct predictions sit on its diagonal. Getting an axis or an end point wrong usually doesn't crash; it silently gives you the wrong data.

Rules

  • arr[i] is row i; arr[:, j] is column j. Both come back 1D.
  • Slices are half-open: arr[r0:r1, c0:c1] takes rows r0 .. r1 - 1 and columns c0 .. c1 - 1.
  • A negative step walks backwards: arr[::-1] reverses the order along axis 0.
  • np.diag(arr) returns arr[i, i] for i = 0 .. min(n_rows, n_cols) - 1, so it also works on non-square arrays.
  • Basic slices return views that share memory with arr. Writing to a view changes arr; call .copy() when you need an independent array.

For example, arr = np.arange(20).reshape(4, 5) is:

[[ 0,  1,  2,  3,  4],
 [ 5,  6,  7,  8,  9],
 [10, 11, 12, 13, 14],
 [15, 16, 17, 18, 19]]

Inputs

  • arr: 2D array of shape (n_rows, n_cols) with n_rows >= 3 and n_cols >= 3 (the tests use shapes like (4, 5)), any numeric dtype.

Expected Return Format

Return a dictionary with these keys:

  • 'row_1': the second row, arr[1], shape (n_cols,)
  • 'col_2': the third column, arr[:, 2], shape (n_rows,)
  • 'subarray': rows 1-2 and columns 2-4, i.e. arr[1:3, 2:5] (columns past the edge are simply dropped)
  • 'diagonal': the main diagonal, shape (min(n_rows, n_cols),)
  • 'reversed': arr with its rows in reverse order (last row first), columns unchanged

Constraints

Use indexing and slicing (plus np.diag); no Python loops.

Follow-up

  • "Advanced" (fancy) indexing uses arrays as indices: arr[[0, 2]] picks rows 0 and 2, arr[arr % 2 == 0] picks the even entries. Unlike slices, both return copies. Why can't they be views?
  • How would you reverse the columns instead, or both axes at once?

Examples

Input: advanced_indexing(np.arange(20).reshape(4, 5))["subarray"]
Output: array([[ 7,  8,  9],
       [12, 13, 14]])

Rows 1 and 2 (the end index 3 is excluded) and columns 2, 3 and 4.

Input: advanced_indexing(np.arange(20).reshape(4, 5))["diagonal"]
Output: array([ 0,  6, 12, 18])

arr[0, 0], arr[1, 1], arr[2, 2], arr[3, 3]: a 4 x 5 array has 4 diagonal entries.

Input: advanced_indexing(np.arange(20).reshape(4, 5))["reversed"][0]
Output: array([15, 16, 17, 18, 19])

After reversing the rows, the last row comes first.

Practice in Python

import numpy as np

def advanced_indexing(arr: np.ndarray) -> dict:
    """
    Select parts of a 2D array with indexing and slicing.

    Args:
        arr: 2D array of shape (n_rows, n_cols), n_rows >= 3 and n_cols >= 3

    Returns:
        dict with keys:
            'row_1':    second row, shape (n_cols,)
            'col_2':    third column, shape (n_rows,)
            'subarray': rows 1-2, columns 2-4 (arr[1:3, 2:5])
            'diagonal': main diagonal, shape (min(n_rows, n_cols),)
            'reversed': arr with its rows in reverse order
    """
    # Your code here
    pass

The interactive editor loads with Python and NumPy. Run your implementation against 8 tests, or use the progressive hints.

More exercises in this section →