Reputation: 2787
Numpy cannot perform the following indexing:
a = np.arange(10)
a[-2: 2]
I'm doing it in a not very elegant way at the moment, is there a trick or oneliner to get that?
Notice that I don't know if I'm facing this scenario in my code, it does happen sometimes, so I'm looking for a dynamic and one-for-all solution, not something for this exact case only.
My generalized slicer, quite long.
def slicer(array, lower_, upper_):
n = len(array)
lower_ = lower_ % n # if negative, you get the positive equivalent. If > n, you get principal value.
roll = lower_
lower_ = lower_ - roll
upper_ = upper_ - roll
array_ = np.roll(array, -roll)
upper_ = upper_ % n
return array_[lower_: upper_]
Upvotes: 2
Views: 1338
Reputation: 231540
In [71]: slicer(np.arange(10),-2,2)
Out[71]: array([8, 9, 0, 1])
It looks like np.r_
does the kind of 'roll' that you want:
In [72]: np.arange(10)[np.r_[-2:2]]
Out[72]: array([8, 9, 0, 1])
In [73]: np.r_[-2:2]
Out[73]: array([-2, -1, 0, 1])
There may be differences between what you expect, and what r_
does. I'll let you study its docs.
Just because you call it slicing, it isn't basic
indexing. However done, the result is a copy
, not a view
. And beware of any kind of extension to multidimensional indexing.
Be careful about seeking an all-case replacement. The use of negative index to mark from-the-end, without wrapping, is so deeply embedded in Python and numpy, that you should always assume that's the default behavior.
In [77]: np.arange(10)[-2:2]
Out[77]: array([], dtype=int64)
Treat your wrapped/roll case as an exception, one the requires special handling.
Upvotes: 3
Reputation: 781
Given that you know the length, you can just add the length of your array to lower and upper if they are < 0. You can then check if upper is smaller than lower, and concatenate if necessary.
def slicer(a, lower, upper):
if lower < 0:
lower += len(a)
if upper < 0:
upper += len(a)
if upper < lower:
return np.concatenate([a[lower:], a[:upper]])
return a[lower:upper]
Upvotes: 0
Reputation: 998
def slicer(a, lower, upper):
if lower < 0:
return np.concatenate((a[lower:], a[:upper]))
else:
return a[lower: upper]
I think it's relatively simple.
Upvotes: 0