Martin McBride, 2021-04-18
Tags slicing step negative index
Categories python language beginning python

Slicing allows us to access part of a list or other sequence. In this article we will see how to:

  • Specify a slice of a list.
  • Use negative indices.
  • Delete or replace a slice of a list.
  • Take a slice of a tuple or string.
  • Loop over a slice.
  • Use steps.

Slicing a list

We already know how to obtain a list element by indexing:

k = [10, 20, 30, 40, 50]
print(k[1])    # 20

Of course, k[1] references element number 1 of list k, which is the second element because elements are numbered from 0.

But we can also obtain a portion of the list, using slicing:

k = [10, 20, 30, 40, 50]
m = k[1:4]
print(m)    # [20, 30, 40]

In this case, k[1:4] is a list that contains elements of k from 1 up to but not including 4. In other words, it contains k[1], k[2], and k[3].

Slicing creates a new list that contains a copy of part of the original list.

There are a couple of extra shortcuts that you can use:

k = [10, 20, 30, 40, 50]
p = k[:2]    # [10, 20, 30]
q = k[3:]    # [40, 50]
r = k[:]     # [10, 20, 30, 40, 50]

The slice k[:2] includes elements of k from the start up to but not including element 2. It is equivalent to k[0:2].

The slice k[3:] includes elements of k from the 3 to the end. It is equivalent to k[3:len(k)].

The slice k[:] includes all the elements of k, from the start to the end. It creates a complete new copy of k.

One more thing that is useful to know about slices is that you don't need to worry about going past the end of the list. The slice will just return the elements that exist, it will not give an index error:

k = [10, 20, 30, 40, 50]
x = k[3:8]       # [40, 50]
y = k[:9]        # [10, 20, 30, 40, 50]
z = k[100:200]   # []

In this case, k[3:8] just returns the last two elements of the list (the equivalent of k[3:5]). k[:9] returns the entire list (the equivalent of k[0:5]). And k[100:200] returns and empty list because the whole slice is outside the range of the list.

Using negative indices

Negative indices are a useful feature of lists (and other sequences such as strings or tuples).

Suppose you wanted to index the last element in a list. You can do this:

k = [10, 20, 30, 40, 50]
print(k[len(k)-1])    # 50

But Python provides a handy shortcut. If you use a negative index, it will count back from the end of the list. So k[-1] represents the last element of the list. k[-2] represents the last but one element of the list, and so on:

k = [10, 20, 30, 40, 50]
print(k[-1])    # 50
print(k[-2])    # 40
print(k[-3])    # 30

This is particularly useful in conjunction with slices. For example, suppose you wanted to create a slice containing every element except the last element. You can do this:

print(k[:-1])   # [10, 20, 30, 40]

Or alternatively, the following code slices the last two elements of the list:

print(k[-2:])   # [40, 50]

Of course, you could do either of these things by calculating the length of the list, but negative indices are a lot neater.

Delete or replace a slice of a list

You can delete a slice of a list like this:

k = [10, 20, 30, 40, 50]
del k[2:4]
print(k)     # [10, 20, 50]

You can also replace a section of the list:

k = [10, 20, 30, 40, 50]
k[2:4] = [3, 4]
print(k)     # [10, 20, 3, 4, 50]

This code replaces the slice [2:3] (which contains the elements [30, 40]) with a new section [3, 4].

Notice that these operations change the original list.

Slicing tuples and strings

You can slice a tuple or a string in exactly the same way as a list. For example:

t = (2, 4, 6, 8)
s = 'Hello world!'
print(t[1:3])     # (4, 6)
print(s[6:11])    # 'world'

You cannot delete or replace slices of tuples or strings, because tuples and strings are immutable types.

Loop over a slice

You can loop over a slice:

k = [10, 20, 30, 40, 50]
for n in k[1:4]:

As you might expect, this code loops over the slice [20, 30, 40], and prints out:


Using steps

Slices have an optional third value, the step.

You might have noticed a similarity between slices and the range function used in for loops. They use very similar logic.

Here is an example:

b = [10, 20, 30, 40, 50 ,60 ,70, 80, 90]
print(b[1:6:2])    # [20, 40, 60]

This code slices from element 1 up to but not including element 6, in steps of 2. So it slices elements 1, 3, and 5, giving the result [20, 40, 60].

Here is another example:

b = [10, 20, 30, 40, 50 ,60 ,70, 80, 90]
print(b[::3])    # [10, 40, 70]

This slices the entire list in steps of 3. So it slices elements 0, 3 and 6.

One final useful thing is that you can use negative steps (just like you can with the range function). The steps through the list backwards:

b = [10, 20, 30, 40, 50 ,60 ,70, 80, 90]
print(b[5:2:-1])    # [60, 50, 40]

This steps from element 5 down to but not including element 2. Since we are counting backwards, the start element is greater than the end element.

You can use other step values:

b = [10, 20, 30, 40, 50 ,60 ,70, 80, 90]
print(b[::-3])    # [90, 60, 30]

This counts from the end of the list down to the start of the list, in steps of 3.

If you found this article useful, you might be interested in the book Python Quick Start or other books by the same author.


Popular tags

2d arrays abstract data type alignment and angle animation arc array arrays bar chart bar style behavioural pattern bezier curve built-in function callable object chain circle classes clipping close closure cmyk colour combinations comparison operator comprehension context context manager conversion count creational pattern data science data types decorator design pattern device space dictionary drawing duck typing efficiency ellipse else encryption enumerate fill filter font font style for loop function function composition function plot functools game development generativepy tutorial generator geometry gif global variable gradient greyscale higher order function hsl html image image processing imagesurface immutable object in operator index inner function input installing iter iterable iterator itertools join l system lambda function len lerp line line plot line style linear gradient linspace list list comprehension logical operator lru_cache magic method mandelbrot mandelbrot set map marker style matplotlib monad mutability named parameter numeric python numpy object open operator optimisation optional parameter or pandas partial application path pattern permutations pie chart polygon positional parameter print pure function python standard library radial gradient range recipes rectangle recursion reduce regular polygon repeat rgb rotation roundrect scaling scatter plot scipy sector segment sequence setup shape singleton slice slicing sound spirograph sprite square str stream string stroke structural pattern subpath symmetric encryption template text text metrics tinkerbell fractal transform translation transparency triangle truthy value tuple turtle unpacking user space vectorisation webserver website while loop zip