I need the last 9 numbers of a list and I'm sure there is a way to do it with slicing, but I can't seem to get it. I can get the first 9 like this:
num_list[0:9]
Any help would be great.
I need the last 9 numbers of a list and I'm sure there is a way to do it with slicing, but I can't seem to get it. I can get the first 9 like this:
num_list[0:9]
Any help would be great.
You can use negative integers with the slicing operator for that. Here's an example using the python CLI interpreter:
>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] >>> a [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] >>> a[-9:] [4, 5, 6, 7, 8, 9, 10, 11, 12]
the important line is a[-9:]
a negative index will count from the end of the list, so:
num_list[-9:]
The last 9 elements can be read from left to right using numlist[-9:], or from right to left using numlist[:-10:-1], as you want.
>>> a=range(17) >>> print a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] >>> print a[-9:] [8, 9, 10, 11, 12, 13, 14, 15, 16] >>> print a[:-10:-1] [16, 15, 14, 13, 12, 11, 10, 9, 8]
Python slicing is an incredibly fast operation, and it's a handy way to quickly access parts of your data.
Slice notation to get the last nine elements from a list (or any other sequence that supports it, like a string) would look like this:
num_list[-9:]
When I see this, I read the part in the brackets as "9th from the end, to the end." (Actually, I abbreviate it mentally as "-9, on")
The full notation is
sequence[start:stop:step]
But the colon is what tells Python you're giving it a slice and not a regular index. That's why the idiomatic way of copying lists in Python 2 is
list_copy = sequence[:]
And clearing them is with:
del my_list[:]
(Lists get list.copy
and list.clear
in Python 3.)
You may find it useful to separate forming the slice from passing it to the list.__getitem__
method (that's what the square brackets do). Even if you're not new to it, it keeps your code more readable so that others that may have to read your code can more readily understand what you're doing.
However, you can't just assign some integers separated by colons to a variable. You need to use the slice object:
last_nine_slice = slice(-9, None)
The second argument, None
, is required, so that the first argument is interpreted as the start
argument otherwise it would be the stop
argument.
You can then pass the slice object to your sequence:
>>> list(range(100))[last_nine_slice] [91, 92, 93, 94, 95, 96, 97, 98, 99]
islice
islice
from the itertools module is another possibly performant way to get this. islice
doesn't take negative arguments, so ideally your iterable has a __reversed__
special method - which list does have - so you must first pass your list (or iterable with __reversed__
) to reversed
.
>>> from itertools import islice >>> islice(reversed(range(100)), 0, 9)
islice allows for lazy evaluation of the data pipeline, so to materialize the data, pass it to a constructor (like list
):
>>> list(islice(reversed(range(100)), 0, 9)) [99, 98, 97, 96, 95, 94, 93, 92, 91]
Here are several options for getting the "tail" items of an iterable:
Given:
n = 9 iterable = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Desired Output:
[2, 3, 4, 5, 6, 7, 8, 9, 10]
We get the latter output using any of the following options:
from collections import deque import itertools import more_itertools # A: Slicing iterable[-n:] # B: Implement an itertools recipe def tail(n, iterable): """Return an iterator over the last *n* items of *iterable*. >>> t = tail(3, 'ABCDEFG') >>> list(t) ['E', 'F', 'G'] """ return iter(deque(iterable, maxlen=n)) list(tail(n, iterable)) # C: Use an implemented recipe, via more_itertools list(more_itertools.tail(n, iterable)) # D: islice, via itertools list(itertools.islice(iterable, len(iterable)-n, None)) # E: Negative islice, via more_itertools list(more_itertools.islice_extended(iterable, -n, None))
Descriptions
iter(iterable)
. itertools
recipe. It is generalized to work on any iterable and resolves the iterator issue in the last solution. This recipe must be implemented manually as it is not officially included in the itertools
module.more_itertools
(install via > pip install more-itertools
); see more_itertools.tail
.itertools
library. Note, itertools.islice
does not support negative slicing. more_itertools
that generalizes itertools.islice
to support negative slicing; see more_itertools.islice_extended
.Which one do I use?
It depends. In most cases, slicing (option A, as mentioned in other answers) is most simple option as it built into the language and supports most iterable types. For more general iterators, use any of the remaining options. Note, options C and E require installing a third-party library, which some users may find useful.