Lists and indexing
Overview
Teaching: 35 min
Exercises: 25 minQuestions
How can I store multiple values?
Objectives
Explain why programs need collections of values.
Write programs that create flat lists, index them, slice them, and modify them through assignment and method calls.
Lists are collections of data
We have already encountered some simple Python types like integers, strings and booleans. Now we will see how we can group multiple values together in a collection – like a list of numbers or a list of names. Collections in Python are containers that are used to store collections of data, and include lists, tuples and dictionaries, which we will cover in future lessons.
- Doing calculations with a hundred variables called
weight_001
,weight_002
, etc., would be at least as slow as doing them by hand. - A list can store many values in a single structure.
- Contained within square brackets
[...]
. - Values separated by commas
,
.
- Contained within square brackets
- Use the built-in function
len
to find out how many values are in a list.
weights = [173, 175, 277, 275, 176]
print('weights:', weights)
print('length:', len(weights))
weights: [173, 175, 277, 275, 176]
length: 5
Use an item’s index to fetch it from a list
- To get the first element of this list we use the index 0 because Python is a 0-based indexing language.
- Indexes are written within square brackets
[]
.
print('zeroth item of weights:', weights[0])
print('fourth item of weights:', weights[4])
zeroth item of weights: 173
fourth item of weights: 176
Reverse indexing, from right to left, also works
weights[-1]
weights[-3]
Using reverse indexing.
How would you extract the letter
l
fromletters
using reverse indexing?letters = list('letters') letters[____]
Solution
letters[-7]
List values can be replaced in place
- Use an index expression on the left of assignment to replace a value.
weights[0] = 265
print('weights is now:', weights)
weights is now: [265, 175, 277, 275, 176]
Basic operations with lists
Similar to strings, lists respond to the + and * operators. These operators also mean concatenation and repetition, respectively, except that the result is a new list, not a string.
What do the following commands print?
concatenate = [1, 2, 3] + [4, 5, 6] print('concatenate is:', concatenate) repetition = ['Hi!'] * 4 print('repetition is:', repetition)
Solution
The program prints
concatenate is: [1, 2, 3, 4, 5, 6] repetition is: ['Hi!', 'Hi!', 'Hi!', 'Hi!']
List methods
- Use
list_name.append
to add items to the end of a list.
primes = [2, 3, 5]
print('primes is initially:', primes)
primes.append(7)
primes.append(9)
print('primes has become:', primes)
primes is initially: [2, 3, 5]
primes has become: [2, 3, 5, 7, 9]
append
is a method of lists.- Like a function, but tied to a particular object.
- Use
object_name.method_name
to call methods. extend
is similar toappend
, but it allows you to combine two lists.
For example:
teen_primes = [11, 13, 17, 19]
middle_aged_primes = [37, 41, 43, 47]
print('primes is currently:', primes)
primes.extend(teen_primes)
print('primes has now become:', primes)
primes.append(middle_aged_primes)
print('primes has finally become:', primes)
primes is currently: [2, 3, 5, 7, 9]
primes has now become: [2, 3, 5, 7, 9, 11, 13, 17, 19]
primes has finally become: [2, 3, 5, 7, 9, 11, 13, 17, 19, [37, 41, 43, 47]]
Note that while extend
maintains the “flat” structure of the list, append
a list to a list makes the result two-dimensional.
Fill in the blanks
Fill in the blanks list methods so that the program below produces the output shown. Hint: start with an empty list
values = ____ values.____(1) values.____() values.____() print('new values:', values)
new values: [1, 3, 5]
- Another useful list method is
.count
which counts the instances of certain object.
For example:
a = ['spam', 'spam', 'eggs', 'spam']
print(a.count('spam'))
print(a.count('eggs'))
print(a.count('bacon'))
print(a.count(5))
3
1
0
0
- We will meet other methods of lists as we go along.
- Use
help(list)
for a preview.
- Use
Use del
to remove items from a list
del list_name[index]
removes an item from a list and shortens the list.- Not a function or a method, but a statement in the language.
primes = [2, 3, 5, 7, 9]
print('primes before removing last item:', primes)
del primes[4]
print('primes after removing last item:', primes)
primes before removing last item: [2, 3, 5, 7, 9]
primes after removing last item: [2, 3, 5, 7]
The empty list contains no values
- Use
[]
on its own to represent a list that doesn’t contain any values.- “The zero of lists.”
- Helpful as a starting point for collecting values, like an empty container. (Empty lists will be very useful in the next episode when we need an empty container to collect values.)
True
orFalse
?What do you think this evaluates to:
type([]) bool([])
Lists may contain values of different types
- A single list may contain numbers, strings, and anything else.
goals = [1, 'Create lists.', 2, 'Extract items from lists.', 3, 'Modify lists.']
Character strings can be indexed like lists
- Get single characters from a character string using indexes in square brackets.
element = 'carbon'
print('zeroth character:', element[0])
print('third character:', element[3])
zeroth character: c
third character: b
But unlike lists, character strings are immutable
- Cannot change the characters in a string after it has been created.
- Immutable: can’t be changed after creation.
- In contrast, lists are mutable: they can be modified in place.
- Python considers the string to be a single value with parts, not a collection of values.
element[0] = 'C'
TypeError: 'str' object does not support item assignment
- Lists and character strings are both sequences. Lists are also collections.
Indexing beyond the end of the collection is an error
- Python reports an
IndexError
if we attempt to access a value that doesn’t exist.- This is a kind of runtime error.
- Cannot be detected as the code is parsed because the index might be calculated based on data.
random_chr = ['±', '!', '@', '#', '$', '%']
print("length of random_chr:", len(random_chr))
print("get the 20th element of random_chr:", random_chr[20])
length of random_chr: 6
IndexError: list index out of range
Slicing python lists
Let’s create a normal, everyday list with letters from a
to h
. Now let’s say that we really want the elements b
, c
, and d
returned in a new list. How do we do that?
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
letters[1:4]
['b', 'c', 'd']
- Remember that
b
is the second element of this list because of the 0-based indexing
Slice bounds
One way to remember how slices work is to think of the indices as pointing between elements, with the left edge of the first character numbered 0.
+---+---+---+---+---+---+---+---+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | +---+---+---+---+---+---+---+---+ 0 1 2 3 4 5 6 7 8 -8 -7 -6 -5 -4 -3 -2 -1
Slice indices have useful defaults
- An omitted second index defaults to the size of the list being sliced.
letters[4:] # list elements from position 4 (included) onwards ... counting from 0!
['e', 'f', 'g', 'h']
- An omitted first index defaults to zero.
letters[:5] # list elements from the beginning to position 5 (excluded)
['a', 'b', 'c', 'd', 'e']
- Lists can also be sliced in reverse order.
print('last item in the list:', letters[-1])
print('last two items in the list:', letters[-2:])
print('everything except the last two items:', letters[:-2])
last item in the list: h
last two items in the list: ['g', 'h']
everything except the last two items: ['a', 'b', 'c', 'd', 'e', 'f']
Fill in the blanks
Fill in the blanks using methods of lists and slicing so that the program below produces the output shown. Hint: start with an empty list
print('first time:', values) values = values[____] print('second time:', values)
first time: [1, 3, 5] second time: [3, 5]
Solution
print('first time:', values) values = values[1:] print('second time:', values)
Stepping through a list
What does the following program print?
elements = ['H', 'He', 'Li', 'B', 'O', 'F', 'Mg', 'P', 'Mn', 'Cu'] print(elements[::2]) print(elements[::-1])
Answer the following questions.
- If we write a slice as
low:high:stride
, what doesstride
do?- What expression would select all of the even-numbered items from a collection?
Solution
The program prints
['H', 'Li', 'O', 'Mg', 'Mn'] ['Cu', 'Mn', 'P', 'Mg', 'F', 'O', 'B', 'Li', 'He', 'H']
stride
is the step size of the slice- The slice
1::2
selects all even-numbered items from a collection: it starts with element1
(which is the second element, since indexing starts at0
), goes on until the end (since noend
is given), and uses a step size of2
(i.e., selects every second element).
Using functions and methods on lists and strings
From strings to lists and back
Given this:
print('string to list:', list('tin')) print('list to string:', ''.join(['g', 'o', 'l', 'd']))
['t', 'i', 'n'] 'gold'
- Explain in simple terms what
list('some string')
does.- What does
'hello'.join(['x','y'])
generate?Solution
list('some string')
“splits” a string into a list of its characters.'xhelloy'
Sort and sorted
What do these two programs print? In simple terms, explain the difference between
sorted(letters)
andletters.sort()
.# Program A letters = list('gold') result = sorted(letters) print('letters is', letters, 'and result is', result)
# Program B letters = list('gold') result = letters.sort() print('letters is', letters, 'and result is', result)
Solution
Program A prints
letters is ['g', 'o', 'l', 'd'] and result is ['d', 'g', 'l', 'o']
Program B prints
letters is ['d', 'g', 'l', 'o'] and result is None
sorted(letters)
returns a sorted copy of the listletters
(the original listletters
remains unchanged), whileletters.sort()
sorts the listletters
in-place and does not return anything.
Another type of collection: Tuples
In Python programming, a tuple is similar to a list: a collection of data elements. The difference between the two is that tuples are immutable, we cannot change the elements of a tuple once it is assigned, whereas a list is mutable, elements can be changed in place. Also, while lists use square brackets []
, tuples use parentheses ()
.
Challenge question
Can you think of any advantages of using tuples over lists? Some of these concepts will become clearer in future chapters.
Solution
- If you have data that doesn’t change, implementing it as tuple will guarantee that it remains write-protected.
- Tuples are faster than lists. If you’re defining a constant set of values and all you’re ever going to do with it is iterate through it, use a tuple instead of a list.
- One good thing about tuples is that they use less memory. Lists use more memory.
- Tuple are better for heterogeneous (different) datatypes and list for homogeneous (similar) datatypes.
Creating a Tuple
- A tuple is created by placing all the items (elements) inside a parentheses
()
, separated by commas. - A tuple can have any number of items and they may be of different types (integer, float, list, string etc.).
- Similar to lists, tuples can also be sliced and indexed, and respond to basic operations.
What would be the ouput of the following commands?
tupl1 = ('d','a','t','a') tupl2 = tupl1 + tuple('is') + (tuple('fun') * 3) print(tupl2)
Solution
('d', 'a', 't', 'a', 'i', 's', 'f', 'u', 'n', 'f', 'u', 'n', 'f', 'u', 'n')
Another advantage of tuples is that they contain immutable elements that can be used as keys
for a dictionary
. With list, this is not possible. We will learn more about keys and dictionaries in a future chapter.
Key Points
A list stores many values in a single structure.
Use an item’s index to fetch it from a list.
Lists are mutable: list values can be replaced by assigning to them.
Appending items to a list lengthens it.
Use
del
to remove items from a list entirely.The empty list contains no values.
Lists may contain values of different types.
Character strings can be indexed like lists.
Python uses 0-based indexing. The first index is zero, the second index is one, and so forth
Indexing beyond the end of the collection is an error.
Tuples are another type of collection, but unlike lists, tuples are immutable.