Bear with me while I explain my question. Skip down to the bold heading if you already understand extended slice list indexing.
In python, you can index lists using slice notation. Here's an example:
>>> A = list(range(10))
>>> A[0:5]
[0, 1, 2, 3, 4]
You can also include a stride, which acts like a "step":
>>> A[0:5:2]
[0, 2, 4]
The stride is also allowed to be negative, meaning the elements are retrieved in reverse order:
>>> A[5:0:-1]
[5, 4, 3, 2, 1]
But wait! I wanted to see [4, 3, 2, 1, 0]
. Oh, I see, I need to decrement the start and end indices:
>>> A[4:-1:-1]
[]
What happened? It's interpreting -1 as being at the end of the array, not the beginning. I know you can achieve this as follows:
>>> A[4::-1]
[4, 3, 2, 1, 0]
But you can't use this in all cases. For example, in a method that's been passed indices.
My question is:
Is there any good pythonic way of using extended slices with negative strides and explicit start and end indices that include the first element of a sequence?
This is what I've come up with so far, but it seems unsatisfying.
>>> A[0:5][::-1]
[4, 3, 2, 1, 0]
As you say very few people fully understand everything that you can do with extended slicing, so unless you really need the extra performance I'd do it the "obvious" way:
rev_subset = reversed(data[start:stop])
It is error-prone to change the semantics of
start
andstop
. UseNone
or-(len(a) + 1)
instead of0
or-1
. The semantics is not arbitrary. See Edsger W. Dijkstra's article "Why numbering should start at zero".Or
Or
When
s
is a sequence the negative indexes ins[i:j:k]
are treated specially:that is why
len(range(10)[4:-1:-1]) == 0
because it is equivalent torange(10)[4:9:-1]
.Ok, I think this is probably as good as I will get it. Thanks to Abgan for sparking the idea. This relies on the fact that None in a slice is treated as if it were a missing parameter. Anyone got anything better?
edit: check for
start==-1
, not0
This is still not ideal, because you're clobbering the usual behavior of -1. It seems the problem here is two overlapping definitions of what's supposed to happen. Whoever wins takes away otherwise valid invocations looking for the other intention.
I believe that the following doesn't satisfy you:
or does it? :-)
Is this satisfactory?
You can use a
slice(start, stop, step)
object, which is such thatis the same as
and, moreover, you can set any of the arguments to
None
to indicate nothing in between the colons. So in the case you give, you can useslice(4, None, -1)
.