Lists
In our first lab, we encountered several distinct data types: int (integers), float (decimal point numbers), complex (complex numbers), str (strings) and bool (booleans). All of these types represent various categories of individual data: a single number, a single string of letters etc. Often, we are interested in collections of data, for example a set of temperatures at which a given experiment has been performed. Python accommodates this requirement by providing us with various data structures that allow us to collate related data into a single object. Lists are one of these data structures.
List basics
A list is an ordered collection of values. The values that comprise a list are usually referred to as the elements or items in that list. To create a list, we enclose the elements (separated by commas) we wish to include in a set of square brackets:
[1, 2, 3, 4, 5][1, 2, 3, 4, 5]
Just like the other data types we have encountered so far, we can store lists in variables with the assignment operator =
some_numbers = [1, 2, 3, 4, 5]
print(some_numbers)
print(type(some_numbers))[1, 2, 3, 4, 5]
list
where see that there is a list type.
This is an example of a list of int, but lists can contain any type of data
some_strings = ['Welcome', 'to', 'CH12002']
print(some_strings)['Welcome', 'to', 'CH12002']
We can mix different types together
a_variety = [5, 'five', 5.0, 5.0 + 0j]
print(a_variety)[5, 'five', 5.0, (5+0j)]
and we can even make a list of lists!
some_numbers = [1, 2, 3, 4, 5]
some_strings = ['Welcome', 'to', 'CH12002']
list_of_lists = [some_numbers, some_strings]
print(list_of_lists)[[1, 2, 3, 4, 5], ['Welcome', 'to', 'CH12002']]
We refer to a list of lists as a nested list.
List indexing
How can we access a single entry in a list? Consider the following example which lists the names of some first-row transition metals
transition_metals = ['vanadium', 'chromium', 'iron']If we want the first entry in the list we can obtain it using list indexing as follows
transition_metals[0]'vanadium'
To index a list we use square brackets [] immediately after the name of the list - no spaces are allowed! Inside the square brackets we put an integer corresponding to the index of the element we want. In programming, we refer to the “entries” of a data structure as its elements.
In Python, we start counting the elements of a data structure from the number zero. The first element of a data structure has index 0, the second 1, and so on. This might be a bit confusing, but you’ll get used to it.
What happens if we try and get the 11th index of transition_metals? There are only three elements, so we get an error!
transition_metals[10]---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
Cell In[11], line 1
----> 1 transition_metals[10]
IndexError: list index out of range
We can get the length of a list using the len function
len(transition_metals)3
To finish off this discussion of list indexing, lets see what happens if we use a negative index.
transition_metals[-1]'iron'
In real life, the “minus first” element doesnt exist, but in Python this takes on a new meaning - the negative sign tells the computer to start counting backwards from the end of the list. So an index of -1 refers to the last element, -2 refers to the second-to-last, and so on.
To index a list of lists we use a new set of brackets [] for each list. Look at the following list
opposites = [['proton', 'electron'], ['positive', 'negative'], ['oxidise', 'reduce']]this contains three lists, each with two elements. Say I want to get the first element of the second list - this would be
opposites[1][0]which tells Python to take the second list (with index 1) and get its first element (index 0).
Modifying lists
Replacing elements
List indexing can be used to modify the elements of a list. This is possible because list objects are what we call mutable - they can change or mutate. Let’s replace the third element of transition_metals with manganese
transition_metals = ['vanadium', 'chromium', 'iron']
print(transition_metals)
transition_metals[2] = 'manganese'
print(transition_metals)['vanadium', 'chromium', 'iron']
['vanadium', 'chromium', 'manganese']
As we’ve seen, you could use an index of -1 instead.
Adding new elements
We can also make lists longer by appending values. To do this, we use the append method of the list. A method is a function which is attached to a particular object. They’re used somewhat similarly, but the syntax differs mostly in the order in which each command is written. Let’s compare len with append to see the difference
transition_metals = [
'vanadium', 'chromium', 'managanese'
]
len(transition_metals)
transition_metals.append('iron')
print(transition_metals)['vanadium', 'chromium', 'managanese', 'iron']
We use the method append by writing .append immediately after the name of the list, and we then feed in our inputs to append - here we just append the string 'iron'.
As well as appending elements to the end of a list, we can also insert elements at any given index in the list using the insert method
transition_metals.insert(0, 'titanium')
print(transition_metals)['titanium', 'vanadium', 'chromium', 'managanese', 'iron']
notice that insert has two arguments - the first is the index where the new element will be located, and the second is the value to use for that new element.
Both insert and append allow us to add single elements, whereas the extend method allows us to add mutiple elements to the end of a list
more_transition_metals = ['cobalt', 'nickel']
transition_metals.extend(more_transition_metals)
print(transition_metals)['titanium', 'vanadium', 'chromium', 'managanese', 'iron', 'cobalt', 'nickel']
where we have providedn a new list to stick onto the end of our current list.
Finally, now that you know about append, insert, and extend, its important to know that you can create an empty list
empty_list = []
print(empty_list)[]
and can append values to it
empty_list.append('absolutely_nothing!')
print(empty_list)['absolutely_nothing!']
Exercise
That’s a lot about lists, but there’s more to come!
As a “break”, play around with the following operations, just like you did for strings.
Create a list containing the letters a, b, and c and carry out the following operations
- Multiply your list by the integer
3 - Multiply your list by the float
3.5 - Add the integer
5to your list using the+operator - Add the list
['d', 'e']to your list using the+operator - Subtract the integer
10from your list using the-operator
Some of the above will give an error, but some will give results that look similar to what we’ve just seen for append and extend.
Removing elements
We now have a range of tools at our disposal for adding elements to a list, but how can we remove them instead? Well, for a start, there’s the remove method
transition_metals.remove('cobalt')
print(transition_metals)['titanium', 'vanadium', 'chromium', 'managanese', 'iron', 'nickel']
Thiss removes the first element which matches the input argument from the list.
Alternatively, there’s the pop method, which allows you to instead specify the index of the element you want to remove.
pop_example = transition_metals.pop(5)
print(pop_example)
print(transition_metals)'cobalt'
['titanium', 'vanadium', 'chromium', 'managanese', 'iron', 'nickel']
Notice that the pop method also returns the value of the removed element. In the example above, we have assigned the output of the pop method to a variable pop_example, which when printed, shows us the removed element.
List slicing
We are now familiar with accessing individual elements of a list, but what if we want to obtain multiple elements at once? Python facilitates this task with a process called list slicing.
transition_metals = ['titanium', 'vanadium', 'chromium', 'managanese', 'iron', 'cobalt', 'nickel']
shorter_list = transition_metals[1:5]
print(shorter_list)['vanadium', 'chromium', 'manganese', 'iron']
We’ve specified two indices 1 and 5 separated by a colon :, and Python has returned a slice containing four elements from our the list - the 2nd, 3rd, 4th, and 5th elements. Interestingly, specifying 5 as the second index doesnt result in the 6th element being included in the slice - to explain why take a look at the box below.
In actual fact, we don’t have to include both the start and end indices - have a go and see what happens using the following example.
transition_metals = ['titanium', 'vanadium', 'chromium', 'managanese', 'iron', 'cobalt', 'nickel']
print(transition_metals[3:])
print(transition_metals[:6])Finally, we can also slice a list in steps by providing a third index which tells python the step size.
transition_metals = ['titanium', 'vanadium', 'chromium', 'managanese', 'iron', 'cobalt', 'nickel']
transition_metals[1:5:2]['vanadium', 'managanese']
which gives us every second element from the 2nd up to but not including the 6th - i.e. our slice will contain the 2nd and 4th elements.
Exercise
Use your knowledge of lists to solve the following problem
Copy the following block of code into a Jupyter notebook:
colours = [['Red', 'Magenta'],
['Cyan', 'Green'],
[['Yellow', 'Blue'], 'White']]Use list indexing to print
Magentafrom thecolourslist.Again, using list indexing, assign the element
Redto a variable calledcolour_1, the elementGreento a variable calledcolour_2, and the elementYellowto a variable calledcolour_3, so that the following line of code runs without error and displays a true statement:
print(f'{colour_1} + {colour_2} -> {colour_3}')The solutions are not to just type out
print('Magenta')
print(f'Red + Green -> Yellow')you need to use list indexing!