# python list index - an easy question

BartC bc at freeuk.com
Tue Dec 20 06:45:07 EST 2016

```On 20/12/2016 00:49, Steve D'Aprano wrote:
> On Mon, 19 Dec 2016 03:21 am, BartC wrote:
>
>> On 18/12/2016 10:59, Paul Götze wrote:
>>> Hi John,
>>>
>>> there is a nice short article by E. W. Dijkstra about why it makes sense
>>> to start numbering at zero (and exclude the upper given bound) while
>>> slicing a list. Might give a bit of additional understanding.
>>>
>>> http://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF

> If you can understand threads, OOP design patterns, binary search or C
> pointers, counting indexes 0, 1, 2, 3, ... should hold no fears for you.

Who's talking about me? In the area of scripting languages that could be
used by people with a wide range of expertise, I would have expected
1-based to be more common.

>> In Python you can also have a third operand for a range, A:B:C, which
>> can mean that B is not necessarily one past the last in the range, and
>> that the A <= i < B condition in that paper is no longer quite true.
>
> You cannot use a simple comparison like A <= i < B to represent a range with
> a step-size not equal to 1. How would you specify the sequence:
>
>     2, 4, 6, 8, 10, 12, 14
>
> as a single expression with ONLY an upper and lower bound?

>     2 <= i <= 14
>
> clearly doesn't work, and nor does any alternative.

I didn't mean that the expression specifies the range, but that an value
in the range satisfies the expression.

>> In fact, A:B:-1 corresponds to A >= i > B, which I think is the same as
>> condition (b) in the paper (but backwards), rather (a) which is favoured.
>
> I have no way of knowing what it corresponds to in your head, but in Python,
> a slice A:B:-1 corresponds to the elements at indices:

I got the idea for a minute that, since A:B:C specifies a set of
indices, and that range(A,B,C) specifies the same set of values, that
they are interchangeable. But of course you can't use x[range(A,B,C)]
and you can't do 'for i in A:B:C'. [In my, ahem, own language, you can
just that...]

>     A, A-1, A-2, A-3, ..., B+1
>
> *in that order*.
>
> py> '0123456789'[7:2:-1]
> '76543'

When A is 7, B is 2 and C is -1, then

for i in range(-1000,1000):
if A >=i > B:
print (i)

displays only the numbers 3,4,5,6,7; the same elements you get, and they
satisfy A >= i > B as I said.

>> Another little anomaly in Python is that when negative indices are used,
>> it suddenly switches to 1-based indexing! Or least, when -index is
>> considered:

> That's silly. You can get whichever correspondence you like by choosing
> values which do or don't match the indices used by Python:
>
>     x = [-3, -2, -1, 0]
>     print x[-1]  # Notice the lack of correspondence
>
>     x = [0, 1, 2, 3]
>     print x[1]  # Notice the correspondence here
>
>     x = [6, 7, 8, 9]
>     print x[1]  # Notice the lack of correspondence here

That point is that indices go 0,1,2,3,... when indexed from the start,
and -1,-2,-3,... when indexed from the end.

That means that the THIRD item from the start has index [2], but the
THIRD item from the end has index [-3].

(So if you reversed a list x, and wanted the same x[i] element you had
before it was reversed, it now has to be x[-(i+1)]. 1-based, the
elements would be x[i] and x[-i], a little more symmetric. But with
N-based, you wouldn't be able to index from the end at all.)

> +---+---+---+---+---+---+
> | P | y | t | h | o | n |
> +---+---+---+---+---+---+
> ....^...........^
> cut here    and here

That's the fence/fencepost thing I mentioned elsewhere. It comes up also
in graphics: if these boxes represent pixels rather than elements, and a
function draws a line from pixel 1 to pixel 4 or fills then in, then
should pixel 4 be filled in or not?

But if you think of these values as continuous measures from the left
edge, rather than as discrete units, and denote them as 1.0 to 4.0, then
it becomes more obvious. The 3 pixels between 1.0 and 4.0 are filled in.

--
bartc
```