Chris
Chris

Reputation: 31256

Construct an advanced slice from string in Python/Numpy

Suppose I have a CLI and would like to construct a slice from the CLI, where the CLI user just inputs a range string.

r = '1:4:2'
axis = '2'

And I have a way of slicing this as follows:

arr = np.zeros((10,10,10))

sliced_arr = eval("arr["+','.join([':',':',r])+"]")

Question: is there a better way to do this?

Upvotes: 2

Views: 83

Answers (3)

norok2
norok2

Reputation: 26906

You can use something like this, which also supports negative indexs:

import numpy as np


def str2slicing(
        slice_str: str,
        index: int,
        n_dim: int):
    assert(-n_dim <= index < n_dim)
    index %= n_dim
    return tuple(
        slice(*map(int, slice_str.split(':'))) if i == index else slice(None)
        for i in range(n_dim))


arr = np.random.randint(1, 100, (10, 10, 10))
sliced_arr = arr[str2slicing('1:4:2', int('2'), arr.ndim)]
print(sliced_arr.shape)
# (10, 10, 2)

(Note that this is pretty much an extension / variation of the other answers: the juice is pretty much this slice(*map(int, slice_str.split(':')))).

Upvotes: 0

Divakar
Divakar

Reputation: 221624

Here's one using r and axis as input arguments -

indexer = [slice(None)]*arr.ndim
indexer[int(axis)] = slice(*map(int,r.split(':')))
out = arr[tuple(indexer)]

Generalizing to handle to any generic indexing string notation in r, it would be -

ax = int(axis)
indexer = [slice(None)]*arr.ndim
o = np.array([0,arr.shape[ax],1])
v = np.array(r.split(':'))
v = np.r_[v,['']*(len(o)-len(v))]
indexer[ax] = slice(*np.where(v=='',o,v).astype(int))
out = arr[tuple(indexer)]

Upvotes: 2

Dani Mesejo
Dani Mesejo

Reputation: 61920

You could build a slice object from the string, and then use numpy.s_:

import numpy as np

r = '1:4:2'
arr = np.zeros((10,10,10))

s = slice(*map(int, r.split(":")))
print(s)

sliced_arr = arr[np.s_[:, :, s]]

Output

slice(1, 4, 2)

Upvotes: 1

Related Questions