You can use choose to make the selection:

>>> z_indices.choose(val_arr)
array([[ 9,  1, 20],
       [ 3,  4, 14],
       [24,  7, 17]])

The function choose is incredibly useful, but can be somewhat tricky to make sense of. Essentially, given an array (val_arr) we can make a series of choices (z_indices) from each n-dimensional slice along the first axis.

Also: any fancy indexing operation will create a new array rather than a view of the original data. It is not possible to index val_arr with z_indices without creating a brand new array.

Answer from Alex Riley on Stack Overflow
Top answer
1 of 4
16

You can use choose to make the selection:

>>> z_indices.choose(val_arr)
array([[ 9,  1, 20],
       [ 3,  4, 14],
       [24,  7, 17]])

The function choose is incredibly useful, but can be somewhat tricky to make sense of. Essentially, given an array (val_arr) we can make a series of choices (z_indices) from each n-dimensional slice along the first axis.

Also: any fancy indexing operation will create a new array rather than a view of the original data. It is not possible to index val_arr with z_indices without creating a brand new array.

2 of 4
7

With readability, np.choose definitely looks great.

If performance is of essence, you can calculate the linear indices and then use np.take or use a flattened version with .ravel() and extract those specific elements from val_arr. The implementation would look something like this -

def linidx_take(val_arr,z_indices):

    # Get number of columns and rows in values array
     _,nC,nR = val_arr.shape

     # Get linear indices and thus extract elements with np.take
    idx = nC*nR*z_indices + nR*np.arange(nR)[:,None] + np.arange(nC)
    return np.take(val_arr,idx) # Or val_arr.ravel()[idx]

Runtime tests and verify results -

Ogrid based solution from here is made into a generic version for these tests, like so :

In [182]: def ogrid_based(val_arr,z_indices):
     ...:   v_shp = val_arr.shape
     ...:   y,x = np.ogrid[0:v_shp[1], 0:v_shp[2]]
     ...:   return val_arr[z_indices, y, x]
     ...: 

Case #1: Smaller datasize

In [183]: val_arr = np.random.rand(30,30,30)
     ...: z_indices = np.random.randint(0,30,(30,30))
     ...: 

In [184]: np.allclose(z_indices.choose(val_arr),ogrid_based(val_arr,z_indices))
Out[184]: True

In [185]: np.allclose(z_indices.choose(val_arr),linidx_take(val_arr,z_indices))
Out[185]: True

In [187]: %timeit z_indices.choose(val_arr)
1000 loops, best of 3: 230 ยตs per loop

In [188]: %timeit ogrid_based(val_arr,z_indices)
10000 loops, best of 3: 54.1 ยตs per loop

In [189]: %timeit linidx_take(val_arr,z_indices)
10000 loops, best of 3: 30.3 ยตs per loop

Case #2: Bigger datasize

In [191]: val_arr = np.random.rand(300,300,300)
     ...: z_indices = np.random.randint(0,300,(300,300))
     ...: 

In [192]: z_indices.choose(val_arr) # Seems like there is some limitation here with bigger arrays.
Traceback (most recent call last):

  File "<ipython-input-192-10c3bb600361>", line 1, in <module>
    z_indices.choose(val_arr)

ValueError: Need between 2 and (32) array objects (inclusive).


In [194]: np.allclose(linidx_take(val_arr,z_indices),ogrid_based(val_arr,z_indices))
Out[194]: True

In [195]: %timeit ogrid_based(val_arr,z_indices)
100 loops, best of 3: 3.67 ms per loop

In [196]: %timeit linidx_take(val_arr,z_indices)
100 loops, best of 3: 2.04 ms per loop
๐ŸŒ
Python Like You Mean It
pythonlikeyoumeanit.com โ€บ Module3_IntroducingNumpy โ€บ AccessingDataAlongMultipleDimensions.html
Accessing Data Along Multiple Dimensions in an Array โ€” Python Like You Mean It
Using an xarray to select Bradโ€™s ... a dimensionality higher than 2. The following code creates a 3-dimensional array: # a 3D array, shape-(2, 2, 2) >>> d3_array = np.array([[[0, 1], ......
๐ŸŒ
NumPy
numpy.org โ€บ devdocs โ€บ user โ€บ basics.indexing.html
Indexing on ndarrays โ€” NumPy v2.6.dev0 Manual
The simplest case of indexing with N integers returns an array scalar representing the corresponding item. As in Python, all indices are zero-based: for the i-th index \(n_i\), the valid range is \(0 \le n_i < d_i\) where \(d_i\) is the i-th element of the shape of the array.
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ python โ€บ numpy-index-3d-array-with-index-of-last-axis-stored-in-2d-array
Numpy: Index 3D array with index of last axis stored in 2D array - GeeksforGeeks
July 23, 2025 - Step 2: We use np.expand_dims to add an extra dimension to z_indices, making its shape (3, 3, 1). This is necessary because take_along_axis requires the indices array to have the same number of dimensions as the array being indexed. Step 3: We use np.take_along_axis to select elements from val_arr along the z-axis (axis=0) using the indices from z_indices_expanded. Step 4: We use np.squeeze to remove the extra dimension added by expand_dims, resulting in the final 2D array result_arr. ... import numpy as np # Create a 3D array of shape (3, 3, 3) val_arr = np.arange(27).reshape(3, 3, 3) # Create a 2D array of indices of shape (3, 3) z_indices = np.array([[1, 0, 2], [0, 0, 1], [2, 0, 1]])
๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 55054603 โ€บ index-a-3d-array-with-2d-array-numpy
python - Index a 3D array with 2D array numpy - Stack Overflow
Our first index array is row_indices = np.arange(source_rows).reshape(-1,1,1). (source_rows is the number of rows in the source, which is 3 in this example) This index array has shape (3,1,1), and actually looks like [[[0]],[[1]],[[2]]]. This is ...
Find elsewhere
๐ŸŒ
Regenerativetoday
regenerativetoday.com โ€บ indexing-and-slicing-of-1d-2d-and-3d-arrays-using-numpy
Indexing and Slicing of 1D, 2D and 3D Arrays Using Numpy โ€“ Regenerative
So, we can select those as before with x[1:]. All the elements are in first and second rows of both the two-dimensional array. Row index should be represented as 0:2. Column index is 1:4 as the elements are in first, second and third column.
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ indexing-multi-dimensional-arrays-in-python-using-numpy
Indexing Multi-dimensional arrays in Python using NumPy | GeeksforGeeks
April 28, 2025 - ... To index a multi-dimensional array you can index with a slicing operation similar to a single dimension array. ... import numpy as np arr_m = np.arange(12).reshape(2, 2, 3) # Indexing print(arr_m[0:3]) print() print(arr_m[1:5:2,::3])
๐ŸŒ
Programiz
programiz.com โ€บ python-programming โ€บ numpy โ€บ array-indexing
Numpy Array Indexing (With Examples)
Let's see an example. import numpy as np # create a 3D array with shape (2, 3, 4) array1 = np.array([[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], [[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]]) # access a specific element of the array element = array1[1, 2, 1] # print the value of ...
๐ŸŒ
Stack Overflow
stackoverflow.com โ€บ questions โ€บ 56152860 โ€บ numpy-3d-array-indexing-works-for-2d-how-to-do-for-3d
python - Numpy 3D array Indexing : Works for 2D, how to do for 3D? - Stack Overflow
May 15, 2019 - Please refer to the figure below: ... key_idx2D = np.array([[1, 2, 1], [2, 2, 2]]) output3D = np.zeros(shape=(key_idx2D.shape[0], len(key_idx), max_out + 1)) key_idx2D = key_idx[np.newaxis, :] # convert to 3D out_idx = out_idx[np.newaxis, :] ...
๐ŸŒ
APXML
apxml.com โ€บ courses โ€บ essential-numpy-pandas โ€บ chapter-3-numpy-array-indexing-slicing โ€บ accessing-single-elements
Access NumPy Array Elements
Visual representation of 2D array indexing. The row index comes first, followed by the column index. The highlighted cell arr2d[1, 1] corresponds to the element at row index 1 and column index 1. The concept naturally extends to arrays with more dimensions. For an N-dimensional array, you provide ...
๐ŸŒ
NumPy
numpy.org โ€บ doc โ€บ stable โ€บ user โ€บ basics.indexing.html
Indexing on ndarrays โ€” NumPy v2.5 Manual
The simplest case of indexing with N integers returns an array scalar representing the corresponding item. As in Python, all indices are zero-based: for the i-th index \(n_i\), the valid range is \(0 \le n_i < d_i\) where \(d_i\) is the i-th element of the shape of the array.
๐ŸŒ
NumPy
numpy.org โ€บ devdocs โ€บ user โ€บ how-to-index.html
How to index ndarrays โ€” NumPy v2.6.dev0 Manual
To get the indices of each maximum or minimum value for each (N-1)-dimensional array in an N-dimensional array, use reshape to reshape the array to a 2D array, apply argmax or argmin along axis=1 and use unravel_index to recover the index of the values per slice: >>> x = np.arange(2*2*3).reshape(2, ...
๐ŸŒ
Pythoninformer
pythoninformer.com โ€บ python-libraries โ€บ numpy โ€บ index-and-slice
PythonInformer - Indexing and slicing numpy arrays
February 4, 2018 - We can index an element of the ... separated by a comma (the index is actually a tuple (2, 1), but tuple packing is used). The example picks row 2, column 1, which has the value 8. This compares with the syntax you might use with a 2D list (ie a list of lists):...
๐ŸŒ
Towards Data Science
towardsdatascience.com โ€บ home โ€บ latest โ€บ introducing numpy, part 2: indexing arrays
Introducing NumPy, Part 2: Indexing Arrays | Towards Data Science
January 13, 2025 - In this article, we'll examine ... Array indexing uses square brackets [], just like Python lists. Learn this step by step with the interactive AI and Data Scientist roadmap. As a refresher from Part 1, here is a graphical representation of a 1D, 2D, and 3D array, with ...
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ python โ€บ numpy-indexing
Numpy Array Indexing - GeeksforGeeks
December 17, 2025 - Here matrix[1, 2] accesses the element in the second row (index 1) and third column (index 2) which is 6. 3D Arrays: It can be visualized as a stack of 2D arrays, we need three indices- Depth: Specifies the 2D slice.