I'm looking for a general method on how to reverse a slice in Python. I read this comprehensive post, which has several nice explanations about how slicing works: Understanding Python's slice notation
Yet I cannot figure out a generalized rule on how to calculate a reversed slice which addresses exactly the same elements in reverse order. I was actually surprised not to find a builtin method doing this.
What I'm looking for is a method reversed_slice that works like this with arbitrary start, stop and step values including negative values:
>>> import numpy as np
>>> a = np.arange(30)
>>> s = np.s_[10:20:2]
>>> a[s]
array([10, 12, 14, 16, 18])
>>> a[reversed_slice(s,len(a))]
array([18, 16, 14, 12, 10])
What I've tried but doesn't work is this:
def reversed_slice(slice_, len_):
"""
Reverses a slice (selection in array of length len_),
addressing the same elements in reverse order.
"""
assert isinstance(slice_, slice)
instart, instop, instep = slice_.indices(len_)
if instep > 0:
start, stop, step = instop - 1, instart - 1, -instep
else:
start, stop, step = instop + 1, instart + 1, -instep
return slice(start, stop, step)
This works fine for step of 1 and when the last addressed element coincides with stop-1. For other cases it does not:
>>> import numpy as np
>>> a = np.arange(30)
>>> s = np.s_[10:20:2]
>>> a[s]
array([10, 12, 14, 16, 18])
>>> a[reversed_slice(s,len(a))]
array([19, 17, 15, 13, 11])
So it seems like I'm missing some relation like (stop - start) % step.
Any help on how to write a general method is greatly appreciated.
Notes:
I do know that there a other possibilities to get a sequence with the same elements reversed, like calling reversed(a[s]). This is not an option here, as I need to reverse the slice itself. The reason is that I work on h5py datasets which do not allow negative step values in slices.
An easy but not very elegant way would be the use of coordinate lists, i.e. a[list(reversed(range(*s.indices(len(a)))))]. This is also not an option due to the h5py requirement that indices in the list must be given in increasing order.
You can specify negative values for step.
>>> s = np.s_[20-2:10-2:-2]
>>> a[s]
array([18, 16, 14, 12, 10])
So you can build the reversed_slice function as follows
>>> def reversed_slice(s):
... """
... Reverses a slice
... """
... m = (s.stop-s.start) % s.step or s.step
... return slice(s.stop-m, s.start-m, -s.step)
...
>>> a = np.arange(30)
>>> s = np.s_[10:20:2]
>>> a[reversed_slice(s)]
array([18, 16, 14, 12, 10])
>>>
>>> a[reversed_slice(reversed_slice(s))]
array([10, 12, 14, 16, 18])
>>>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With