List slicing#

Given a list, it is often useful to be able to extract a sublist from it. One way of achieving this in Python is using slicing. This “cuts out” a sublist of a given list. The notation for it is list_to_slice[start:stop:step]. We often leave out step, in which case consecutive elements will be selected. We can also leave out start or stop, in which case they will default to “start of the list” or “end of the list”, and we can index from the end using negative numbers.

Don’t be too concerned with memorising the details - just remember it’s possible, and often useful, and refer back to this when you need to!

my_list = [0, 1, 2, 3, 4, 5]
# slice from the start of the list, stopping before the 3rd element
my_list[0:2]
[0, 1]
# slice from the second element, stopping before the fifth element
my_list[1:4]
[1, 2, 3]
# slice from the second element to the end
my_list[1:]
[1, 2, 3, 4, 5]
# slice from the start of the list, stopping before the second-last element
my_list[:-2]
[0, 1, 2, 3]
# slice from the start of the list, stopping before the last element,
# and only taking every other element
my_list[0:-1:2]
[0, 2, 4]

Array slicing#

You may find that you slice arrays more often than lists; it is a very natural way of selecting a subset of some data. Suppose I have a 2-dimensional array, i.e. a matrix.

import numpy as np

mat = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])

mat
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Input In [7], in <cell line: 1>()
----> 1 import numpy as np
      3 mat = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
      5 mat

ModuleNotFoundError: No module named 'numpy'

I want to select the sub-matrix with entries 6, 7, 10, and 11 from it. I can slice the rows of mat:

mat[1:]
array([[ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])

To slice the columns at the same time, just use a comma:

# slice from the second row to the end, and from the second to the third column

mat[1:, 1:3]
array([[ 6,  7],
       [10, 11]])

This idea extends to higher-dimensional arrays; just add extra commas. If you want to take the whole array in a particular dimension (not slice in that “direction”), use a : to select from the start to the finish.

Here’s an example using a 3-dimensional array, which you can think of as a cuboid of numbers, where we select the second row, all columns, and last two “depths” using slicing. Note that what is a “row”, “column”, or “depth” depends entirely on your perspective, and it would be more precise to say “first/second/third dimension”.

# make the cuboid contain 0 ... 59
nums = np.array(range(60)) 

# "reshape" the list 0 .. 59 into a 3x4x5 cuboid
cuboid = nums.reshape((3, 4, 5))

# show the cuboid
cuboid
array([[[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]],

       [[20, 21, 22, 23, 24],
        [25, 26, 27, 28, 29],
        [30, 31, 32, 33, 34],
        [35, 36, 37, 38, 39]],

       [[40, 41, 42, 43, 44],
        [45, 46, 47, 48, 49],
        [50, 51, 52, 53, 54],
        [55, 56, 57, 58, 59]]])
cuboid[1, :, -2:]
array([[23, 24],
       [28, 29],
       [33, 34],
       [38, 39]])

Assignment with arrays and lists#

There is a minor complication when using the assignment operator, = with arrays and lists. If we attempt to define a new list (or array) using an old one we actually create a link to the original not a new copy. This means that changing the original effectively changes the new variable at the same time, for example

old = [1,2,3,4]

new = old

old[1] = 6

new
[1, 6, 3, 4]

Sometimes this is desirable but more often than not we wish to have a fresh copy which is not updated when the old variable is. To accomplish this we can assign using a full array slice which forces a copy of the data from old to new.

old = [1,2,3,4]

new[:] = old

old[1] = 6

new
[1, 2, 3, 4]