20

Suppose we have this list:

>>> a = [x for x in range(10)]
>>> print(a)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Separately, both ways to slice work as expected:

>>> a[3:8]
[3, 4, 5, 6, 7]

>>> a[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

But, when combined:

>>> a[3:8:-1]
[]

I would expect it to be [7, 6, 5 ,4, 3] or perhaps [6, 5, 4, 3, 2] (if reversing happened first). It is also interesting to consider what happens when either start or stop parameters are not passed:

>>> a[:5:-1]
[9, 8, 7, 6]

This is almost what I would expect, only its one item short. Tested this with numpy and it seems to behave in the same way.

Whats going on here?

user3105173
  • 435
  • 4
  • 15
  • 5
    Did you try `a[8:3:-1]`? – AKX Dec 02 '19 at 22:20
  • 1
    if you had correctly understood first two expressions `a[:: -1]` and `a[3:8]` *then* your expected result should come from `a[3: 8][:: -1]` expression, rather than `a[3: 8: -1]` – Grijesh Chauhan Dec 03 '19 at 07:00
  • Also: [Why does extended slicing not reverse the list?](https://stackoverflow.com/q/56959836/7851470) – Georgy Dec 03 '19 at 09:38

3 Answers3

20

With

a[3:8:-1]

The start and stop positions of the slice aren't adjusted based on the step. With a negative step, you're having it go backwards from 3, but there are no elements with indices in the range 3 to 8 counting back from 3, so you get an empty list.

You need to set the start and stop accordingly:

a[8:3:-1]

Which will count back from 8 to 4.

Carcigenicate
  • 43,494
  • 9
  • 68
  • 117
7

a[3:8:-1] instructs python to start from 3 and go to 8 by steps of -1

This creates an empty list: it's not possible to reach 8 from 3 by adding -1 (just like list(range(3,8,-1)) which gives an empty list too)

When you do a[:5:-1] then start is the default start, which python sets to "end of list" so it "works"

Same as when you do a[::-1] the start & stop are the default ones, and python understands that they're from end to start (else this notation wouldn't be useable)

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
4

This behavior is explained in the documentation.

The slice of s from i to j is defined as the sequence of items with index k such that i <= k < j. If i or j is greater than len(s), use len(s). If i is omitted or None, use 0. If j is omitted or None, use len(s). If i is greater than or equal to j, the slice is empty.

The slice of s from i to j with step k.... stopping when j is reached (but never including j). When k is positive, i and j are reduced to len(s) if they are greater. When k is negative, i and j are reduced to len(s) - 1 if they are greater. If i or j are omitted or None, they become “end” values (which end depends on the sign of k).

Community
  • 1
  • 1
sammy
  • 857
  • 5
  • 13