question about slicing with a step length

J

John Salerno

Given:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

can someone explain to me why

numbers[10:0:-2] results in [10, 8, 6, 4, 2]?

I thought the first index, whether going forward or backward, was
inclusive. And there is no index of 10 in this list, so what is it
referring to?

Thanks.
 
J

James Stroud

John said:
Given:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

can someone explain to me why

numbers[10:0:-2] results in [10, 8, 6, 4, 2]?

I thought the first index, whether going forward or backward, was
inclusive. And there is no index of 10 in this list, so what is it
referring to?

Thanks.

Its referring to right after the end of the list, just as the 0 refers
to just before the start of the list. The word "slice" is supposed to
suggest cutting between (or before or after) elements.

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 
S

Steven Bethard

John said:
Given:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

can someone explain to me why

numbers[10:0:-2] results in [10, 8, 6, 4, 2]?

I always have trouble with these. Given the docs[1]:

"""
The slice of s from i to j with step k is defined as the sequence of
items with index x = i + n*k such that $0 \leq n < \frac{j-i}{k}$. In
other words, the indices are i, i+k, i+2*k, i+3*k and so on, stopping
when j is reached (but never including j). If i or j is greater than
len(s), use len(s). If i or j are omitted then they become ``end''
values (which end depends on the sign of k). Note, k cannot be zero.
"""

I would expect that we're looking at the indices
10 + n*(-2)
such that
0 <= n < (0-10)/-2
0 <= n < 5
which should be indices 10, 8, 6, 4, 2 which would skip 10 so as not to
provoke an IndexError, and then give you the list [9, 7, 3, 5, 1].

Clearly that's not what happens. Looks like there's a rule in there
somewhere that says if the start is greater than the length, use the
length instead. That would mean starting at 9 instead of 10, and
getting the indices 9, 7, 5, 3, 1 which would give you the list [10, 8,
6, 4, 2]

Hmm... Is there some documentation I'm missing that says the start
index will be replaced with the length if necessary? I'll file a doc
patch if it looks like I'm not just missing something somewhere else...

STeVe

[1]http://docs.python.org/lib/typesseq.html
 
J

John Salerno

James said:
John said:
Given:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

can someone explain to me why

numbers[10:0:-2] results in [10, 8, 6, 4, 2]?

I thought the first index, whether going forward or backward, was
inclusive. And there is no index of 10 in this list, so what is it
referring to?

Thanks.

Its referring to right after the end of the list, just as the 0 refers
to just before the start of the list. The word "slice" is supposed to
suggest cutting between (or before or after) elements.

But why isn't the first index inclusive in this case?
 
S

Steven D'Aprano

John said:
Given:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

can someone explain to me why

numbers[10:0:-2] results in [10, 8, 6, 4, 2]?

I think the documentation is misleading/incomplete when
it comes to negative strides for extended slices.

The relevent sections are here:

http://www.python.org/doc/2.3.5/ref/types.html

Some sequences also support "extended slicing" with a
third "step" parameter: a[i:j:k] selects all items of a
with index x where x = i + n*k, n >= 0 and i <= x < j.
[end quote]

and from http://www.python.org/doc/2.3.5/ref/slicings.html

It is not an error if i or j lie outside the range of
valid indexes (such items don't exist so they aren't
selected).
[end quote]


The documentation suggests that, given a slice
[10:0:-2], Python looks up indices:

10 + 0*-2, 10 + 1*-2, 10 + 2*-2, ...

or 10, 8, 6, 4, 2, 0, ...

but since *none* of these indices is within the limits
10 <= x and x < 0, the documentation suggests that
the result should be the empty list.

The indices actually selected are:

9, 7, 5, 3, 1

at which point I give up and throw my hands in the air
and promise never to use negative strides with extended
slices.
 
J

James Stroud

John said:
James said:
John said:
Given:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

can someone explain to me why

numbers[10:0:-2] results in [10, 8, 6, 4, 2]?

I thought the first index, whether going forward or backward, was
inclusive. And there is no index of 10 in this list, so what is it
referring to?

Thanks.


Its referring to right after the end of the list, just as the 0 refers
to just before the start of the list. The word "slice" is supposed to
suggest cutting between (or before or after) elements.

But why isn't the first index inclusive in this case?
You skipped it with the -2 step size.

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 
?

=?iso-8859-1?B?QW5kcuk=?=

Steven said:
John said:
Given:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

can someone explain to me why

numbers[10:0:-2] results in [10, 8, 6, 4, 2]?

I think the documentation is misleading/incomplete when
it comes to negative strides for extended slices.
Agreed!

[snip...]

The indices actually selected are:

9, 7, 5, 3, 1

at which point I give up and throw my hands in the air
and promise never to use negative strides with extended
slices.
!!! Agreed!

I found this which seems an appropriate description:
"""
An extended slice of list x of length n in the form x[j:k:i] selects
every i-th element starting with and including the element at index j
and ending with but not including the element at index k. When either
index is negative, the value of n is added to it before any further
processing occurs. When either index is missing or lies outside of the
list bounds, the minimum or maximum inclusive index is used
automatically.
"""
source: https://trove.homeip.net/ExtendedSlices
André
 
J

John Salerno

André said:
An extended slice of list x of length n in the form x[j:k:i] selects
every i-th element starting with and including the element at index j

This makes it sound like the index of 10 should be inclusive.

When either index is missing or lies outside of the
list bounds, the minimum or maximum inclusive index is used
automatically.

So does that mean that the example actually is wrong, and Python is
compensating? I tried numbers[9:0:-2] and it returned the same value as
if I had used 10 as the first index, so perhaps 10 shouldn't be there
after all.
 
T

Terry Reedy

John said:
Given:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
can someone explain to me why
numbers[10:0:-2] results in [10, 8, 6, 4, 2]?

It appears that s[i:j:-1] is s[(j+1):(i+1)] .reverse()'ed. For 'numbers',
this is 10, 9, 8, 7, 6, 5, 4, 3, 2]. Then take every other item. Why the
+1? Don't know and not my intuitive expectation. I just know that
extended slicing was developed for and until recently pretty much
restricted to numeric (now numpy).

Steven D'Aprano
I think the documentation is misleading/incomplete when
it comes to negative strides for extended slices.

and Andre "Agreed!" also, and you three aren't the only ones. Maybe some
day I will read the source, think about it more, and post a suggested
revision for comment ... or maybe someone will beat me to it.

Terry Jan Reedy
 
?

=?iso-8859-1?B?QW5kcuk=?=

Terry said:
John said:
Given:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
can someone explain to me why
numbers[10:0:-2] results in [10, 8, 6, 4, 2]?

It appears that s[i:j:-1] is s[(j+1):(i+1)] .reverse()'ed. For 'numbers',
this is 10, 9, 8, 7, 6, 5, 4, 3, 2]. Then take every other item. Why the
+1? Don't know and not my intuitive expectation. I just know that
extended slicing was developed for and until recently pretty much
restricted to numeric (now numpy).
It's not simply "+1".
a = range(10)
a[9:0:-2]
[9, 7, 5, 3, 1]
[9, 7, 5, 3, 1]
[9, 7, 5, 3, 1]
[9, 7, 5, 3, 1]
Steven D'Aprano

and Andre "Agreed!" also, and you three aren't the only ones. Maybe some
day I will read the source, think about it more, and post a suggested
revision for comment ... or maybe someone will beat me to it.

I, myself, think that the slicing behaviour is broken in this case.
From the little I understand (without looking at the source),
adjustment on the boundaries of the slicing "request" (the first 2
numbers) is done first, to make them positive and, I believe, ensure
that they do not extend beyond the boundaries of the sequence. Then,
the actual stepping through is performed.

In my (most likely not-well informed enough opinion), the behaviour
should be the following:
from [i: j: k],
if k > 0 and j <= i : return []
if k< 0 and j >= i : return []
otherwise, build the following list of numbers:
i, i+k, i+2*k,
until i +n*k >= j (if k>0; use <= if k<0)
where the last number is excluded, i.e.
[0: 2: 1] = list(0, 1)
*Then*, exclude from the list just built any negative numbers, or any
number greater than the length of the sequence to be sliced.

So, [10:0:-2] would yield the following list of numbers
[10, 8, 6, 4, 2] before trimming; applying this to
range(10), would end up with result in trimming "10" from the list
built.
Thus, we are looking at indices [8, 6, 4, 2] of range(10), which happen
to be the numbers [8, 6, 4, 2] in this case. We should end up with
the same list if we ask for [42:0:-2]. This is not the observed
behaviour,
as we get [9, 7, 5, 3, 1].
If we ask Python to do
we get
[0, 2, 4, 6, 8]
which is correct. It seems to me that the following (pseudo-code, not
valid Python)
a[2:10:2] == a[8:0:-2].reversed()
should be true, just like
a[1:10:1] == a[9:0:-1].reversed()
is true.

I *suspect* that "boundary adjustments" are performed first before
creating a sequence of indices, so that there is less "trimming" (as
described above) for the sake of efficiency ... and that this is not
done properly.

Then again, perhaps I simply don't understand what slices are supposed
to do....

André
 
S

Steven Bethard

John said:
Given:

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

can someone explain to me why

numbers[10:0:-2] results in [10, 8, 6, 4, 2]?

I've filed a bug report:
http://bugs.python.org/1446619

I suggest the following rewording for extended slices:

"""
To get the slice of s from i to j with step k, first
determine the bounds. If k is positive, and i or j is
greater than len(s), use len(s). If k is negative, and
i or j is greater than len(s)-1, use len(s)-1. Note, k
cannot be zero. If i or j are omitted then they become
``end'' values (which end depends on the sign of k).

The slice of s from i to j with step k is then defined
as the sequence of items with index x = i + n*k such
that 0 <= n < (j - i)/k. In other words, the indices
are i, i+k, i+2*k, i+3*k and so on, stopping when j is
reached (but never including j).
"""

I believe that properly explains the behavior, but if I've messed it up
(entirely likely), please suggest alternate wording on the bug report.

STeVe
 
T

Terry Reedy

Terry said:
It appears that s[i:j:-1] is s[(j+1):(i+1)] .reverse()'ed. For
'numbers',
this is 10, 9, 8, 7, 6, 5, 4, 3, 2]. Then take every other item. Why
the
+1? Don't know and not my intuitive expectation. I just know that
extended slicing was developed for and until recently pretty much
It's not simply "+1".

Yes it is. Boundary adjustment follows, as implied by what I wrote.
a = range(10)
a[9:0:-2]
a[10:0:-2]
a[11:0:-2]
a[42:0:-2]

are all [9, 7, 5, 3, 1] because a[1:10] == a[1:11] == a[1:12] == a[1:43] ==
[1,3,5,7,9], which is then reversed.

Terry Jan Reedy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top