1

I've looked through many different answers for indexing 2D and 3D arrays and I can't quite find a simple solution to my problem. I have a 3D array and have a list of 3-component indices (ix, iy, iz). I would like a list of values from the array, where each value is chosen using the one of the 3-component indices.

I've been able to solve the problem by flattening the array with reshape() and np.apply_along axis, but this seems inelegant, especially since I need to define a function to convert the 3-component indices to 1-component indices.

import numpy as np
data = np.arange(125).reshape(5,5,5)
indices = np.array(((0, 0, 0), (4, 4, 4), (0, 0, 4)), dtype=int)

# For-loop implementation
values = []
for i in indices:
    values.append(data[i[0], i[1], i[2]])
print(values)


# My inelegant numpy implementation
def three_to_one(index3d,dim):
    return index3d[0]*dim[1]*dim[2] + index3d[1]*dim[2] + index3d[2]

indices_1d = np.apply_along_axis(three_to_one, 1, indices, data.shape)
data_flat = data.reshape(-1)
values = data_flat[indices_1d]
print(values)
1
  • 1
    As a general rule I regard apply_along to be in-elegant. Under the covers it's just an iterator.. I doubt if it's any faster. Commented Oct 17, 2023 at 18:16

2 Answers 2

3

Starting with Python-3.11, this works:

data[*indices.T]

In older python versions, this is equivalent:

data[tuple(indices.T)]

The trick is that you can give one sequence per dimension, comma-separated or as a tuple (not a list!). You see this in use with np.nonzero

data = np.random.random((4, 5, 6))
above = data[np.nonzero(a > 0.75)]
Sign up to request clarification or add additional context in comments.

7 Comments

This is a SyntaxError for me - which version of Python are you using?
@NickODell Interesting. Python-3.11.5 with Numpy-1.25.2. What's it on your side?
@NickODell I also get a syntax error in 3.6. I don't have any versions in-between and in a quick scan of the release notes I couldn't find the relevant change. Would be interesting to know which version is required
This works for me with Python-3.11.5 with Numpy-1.25.2
@WaterMolecule Thanks. It doesn't work in Python 3.10.12, so that just gave me one version to check. The behavior is described in the Implications section of PEP 646 – Variadic Generics. So this is a Python 3.11 feature.
|
2

You can do this by transposing indices and using tuple() to interpret each column of indices as an index into data.

>>> data[tuple(indices.T)]
array([  0, 124,   4])

3 Comments

I've been going through all the "advanced" array indexing functions in numpy and the solution wasn't there at all!
The underlying feature is that for all indexing, x[i,j], x[(i,j)], x[tuple(i,j)] are the same. Comma, in most contexts, makes a tuple.
From the lead paragraph of the basic indexing page: Note that in Python, x[(exp1, exp2, ..., expN)] is equivalent to x[exp1, exp2, ..., expN]; the latter is just syntactic sugar for the former. Use of tuples in indexing applies to scalars, slices (basic indexing), as well as arrays (advanced indexing). numpy.org/doc/stable/user/basics.indexing.html @WaterMolecule

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.