Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reversing an arbitrary slice in Python

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.

like image 722
eaglesear Avatar asked Aug 29 '26 10:08

eaglesear


1 Answers

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])
>>> 
like image 148
Sunitha Avatar answered Aug 31 '26 01:08

Sunitha