1

Given any N-tuple of slices (aka N-D slice) in NumPy how to convert it to corresponding indexes of N-D array represented as tuple of 1D arrays (indexes along each axes)? E.g. if we have np.nd_slice_to_indexes next code:

import numpy as np
print(np.nd_slice_to_indexes(np.s_[1 : 3]))
print(np.nd_slice_to_indexes(np.s_[1 : 3, 5 : 11 : 2]))

should print

(array([1, 2]),)
(array([1, 1, 1, 2, 2, 2]), array([5, 7, 9, 5, 7, 9]))

It is common for NumPy to represent indexes of N-D array as N-tuple of 1-D arrays of same length (each element of k-th array in tuple represents next index along k-th dimension). E.g. np.nonzero returns such N-tuple in code

print(np.nonzero([[0, 1, 1], [1, 1, 0]])) # Non-zero elements in 2D array.
# (array([0, 0, 1, 1], dtype=int64), array([1, 2, 0, 1], dtype=int64))

Same behavior should be achieved like in Pythonic function below, but in a more efficient (performant) way:

Try it online!

import numpy as np

def nd_slice_to_indexes(nd_slice):
    assert type(nd_slice) in [tuple, slice], type(nd_slice)
    if type(nd_slice) is not tuple:
        nd_slice = (nd_slice,)
    def iter_slices(slices):
        if len(slices) == 0:
            yield ()
        else:
            for i in range(slices[0].start, slices[0].stop, slices[0].step or 1):
                for r in iter_slices(slices[1:]):
                    yield (i,) + r
    *res, = np.vstack(list(iter_slices(nd_slice))).T
    return tuple(res)

print(nd_slice_to_indexes(np.s_[1 : 3]))
print(nd_slice_to_indexes(np.s_[1 : 3, 5 : 11 : 2]))
print(nd_slice_to_indexes(np.s_[1 : 3, 5 : 11 : 2, 8 : 14 : 3]))
# (array([1, 2]),)
# (array([1, 1, 1, 2, 2, 2]), array([5, 7, 9, 5, 7, 9]))
# (array([1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2]), array([5, 5, 7, 7, 9, 9, 5, 5, 7, 7, 9, 9]), array([ 8, 11,  8, 11,  8, 11,  8, 11,  8, 11,  8, 11]))
3
  • 1
    Look at np.ogrid and np.mgrid. Commented Sep 28, 2020 at 7:10
  • @hpaulj Thanks! Works! Added your suggestion regarding np.mgrid as this answer. Commented Sep 28, 2020 at 7:24
  • @hpaulj Although looking at code of np.mgrid it could be the case that it is not very performant implementation. Commented Sep 28, 2020 at 8:42

1 Answer 1

1

Thanks to suggestion of @hpaulj solved task efficiently using np.mgrid.

Try it online!

import numpy as np

def nd_slice_to_indexes(nd_slice):
    grid = np.mgrid[{tuple: nd_slice, slice: (nd_slice,)}[type(nd_slice)]]
    return tuple(grid[i].ravel() for i in range(grid.shape[0]))
    
print(nd_slice_to_indexes(np.s_[1 : 3]))
print(nd_slice_to_indexes(np.s_[1 : 3, 5 : 11 : 2]))
print(nd_slice_to_indexes(np.s_[1 : 3, 5 : 11 : 2, 8 : 14 : 3]))
# (array([1, 2]),)
# (array([1, 1, 1, 2, 2, 2]), array([5, 7, 9, 5, 7, 9]))
# (array([1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2]), array([5, 5, 7, 7, 9, 9, 5, 5, 7, 7, 9, 9]), array([ 8, 11,  8, 11,  8, 11,  8, 11,  8, 11,  8, 11]))
Sign up to request clarification or add additional context in comments.

2 Comments

Might be not efficient, didn't do timings, not sure if np.mgrid is impelemented to be really fast.
How should this code be adjusted for processing a list of slices, e.g. as returned from scipy.ndimage.find_objects?

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.