The Artima Developer Community
Sponsored Link

Python Buzz Forum
Negative Sequence Indices in Python

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Thomas Guest

Posts: 236
Nickname: tag
Registered: Nov, 2004

Thomas Guest likes dynamic languages.
Negative Sequence Indices in Python Posted: Aug 1, 2016 9:46 AM
Reply to this message Reply

This post originated from an RSS feed registered with Python Buzz by Thomas Guest.
Original Post: Negative Sequence Indices in Python
Feed Title: Word Aligned: Category Python
Feed URL: http://feeds.feedburner.com/WordAlignedCategoryPython
Feed Description: Dynamic languages in general. Python in particular. The adventures of a space sensitive programmer.
Latest Python Buzz Posts
Latest Python Buzz Posts by Thomas Guest
Latest Posts From Word Aligned: Category Python

Advertisement

Supply a negative index when accessing a sequence and Python counts back from the end. So, for example, my_list[-2] is the penultimate element of my_list, which is much better than my_list[len(my_list)-2] or even *(++my_list.rbegin()).

That final example uses one of C++’s reverse iterators. It gets the penultimate element of a collection by advancing an iterator from the reversed beginning of that collection. If you’re addicted to negative indices you can use them with C++ arrays, sort of.

Negative array indices in C++
#include <iostream>

int main()
{
    char const * domain = "wordaligned.org";
    char const * end = domain + strlen(domain);
    std::cout << end[-3] << end[-2] << end[-1] << '\n';
    return 0;
}

Compiling and running this program outputs the string “org”.

Going back to Python, the valid indices into a sequence of length L are -L, -L+1, … , 0, 1, … L-1. Whenever you write code to calculate an index used for accessing a sequence, and especially if you’re catching any resulting IndexErrors, it’s worth checking if the result of the calculation can be negative, and if — in this case — you really do want the from-the-back indexing behaviour.

 
 
 
 
0
1
2
3
4
5
6
7
8
9
10
11
12
13
 
 
 
 
W
O
R
D
A
L
I
G
N
E
D
 
 
 
 
-14
-13
-12
-11
-10
-9
-8
-7
-6
-5
-4
-3
-2
-1
 
 
 
 

The power of negative indices increases with slicing. Take a slice of a sequence by supplying begin and end indices.

>>> domain = 'wordaligned.org'
>>> domain[4:9]
'align'
>>> domain[4:-4]
'aligned'
>>> digits = list(range(10))
>>> digits
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> digits[3:4]
[3]
>>> digits[1:-1]
[1, 2, 3, 4, 5, 6, 7, 8]

Omitting an index defaults it to the end of the sequence. Omit both indices and both ends of the sequence are defaulted, giving a sliced copy.

>>> domain[-3:]
'org'
>>> domain[:4]
'word'
>>> digits[:]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

I prefer the list(digits) form for copying digits but you should certainly be familiar with the digits[:] version.

You can supply any indices as slice limits, even ones which wouldn’t be valid for item access. Imagine laying your sequence out on an indexed chopping board, slicing it at the specified points, then taking whatever lies between these points.

>>> digits[-1000000]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> digits[1000000]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
>>> digits[-1000000:1000000]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Sequence slicing also takes a step parameter.

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

This parameter too can be negative. The sign of the step affects which limiting values the begin and end slice parameters default to. It’s subtle behaviour, but you soon get used to it.

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

How do you reverse a string? Slice it back to front!

>>> domain[::-1]
'gro.dengiladrow'

To recap: the default slice limits are the start and end of the sequence, 0 and -1, or -1 and 0 if the step is negative. The default step is 1 whichever way round the limits are. When slicing, s[i:j:k], i and j may take any integer value, and k can take any integer value except 0.

The zero value creates another interesting edge case. Here’s a function to return the last n items of a sequence.

>>> def tail(xs, n)
...     return xs[-n:]
...

It fails when n is 0.

>>> tail(digits, 3)
[7, 8, 9]
>>> tail(digits, 2)
[8, 9]
>>> tail(digits, 1)
[9]
>>> tail(digits, 0)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

By the way, we’ve already seen slicing working well with lists and strings. It also works nicely with range objects.

>>> r = range(10)
>>> r[::2]
range(0, 10, 2)
>>> r[1::2]
range(1, 10, 2)

Read: Negative Sequence Indices in Python

Topic: Reading ASCII file in Python3.5 is 2-3x faster as bytes than string Previous Topic   Next Topic Topic: Watch This Space

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use