Lists

Jon Reades

What’s in a List?

In the same way that a paper shopping list holds many ‘types’ of shopping in one place, a Python list holds many ‘types’ of data in one place.

myList = [1, 3, 5, 7]     # homogenous list
myList = [1, "dog", 7.01] # heterogenous list 
myList = []               # empty list

Python lists are always recognisable by their “square brackets”: [...]

What’s in a List? (Part 2)

In fact, when I say lists can hold many types of data, I should have said that they can hold any type of data:

x = 3
y = "Foo"
z = ["A", "list", 42]

a = [x, y, z] # Holds x, y, *and* list z

The output of print(a) is:

[3, 'Foo', ['A', 'list', 42]]

Accessing Lists

Using List Indexes

geographers = ["Massey", "Harvey", "Rose"]

Lists are ‘indexed’ numerically from the zero-th element:

geographers [ 0 1 2 ]
Massey 1 Harvey 2 Rose 3
print(geographers[1]) # Harvey
print(geographers[2]) # Rose
print(geographers[3]) # Error: List index out of range

Interpolation

We can also use variables as list indexes:

geographers = ["Massey", "Harvey", "Rose"]
i = 0
print(geographers[i]) # Massey

Anything that evaluates (i.e. resolves) to a number can be used as an index:

i = 1
print(geographers[i+1]) # Rose
print(geographers[ (i-2+1)*2 ]) # Massey

Countdown!

We can ‘count’ backwards from the end of the list using negative numbers:

geographers = ["Massey", "Harvey", "Rose"]
print( geographers[-1] ) # Rose
print( geographers[-2] ) # Harvey

Does Not Compute!

Errors can be scary… but informative!

geographers = ["Massey", "Harvey", "Rose"]
print( geographers[4] )

IndexError: list index out of range

And then try:

print( geographers[1.25] )

TypeError: list indices must be integers or slices, not float

Notice that Python gives us important hints about the source of the problem!

Slicing & Dicing Lists

You can access more than one element at a time using a slice:

geographers = ["Massey", "Harvey", "Rose"]
print( geographers[0:2] ) # ['Massey','Harvey']
print( geographers[1:] )  # ['Harvey', 'Rose']
print( geographers[-2:] ) # ['Harvey', 'Rose']

The syntax for a slice is: list[ <start_idx>, <end_idx> ], but end_idx is not included in the slice. And notice:

print( geographers[1:2] ) # ['Harvey']
print( geographers[1] )   #   Harvey

Test Yourself

What do you think this will produce?

geographers = ["Massey", "Harvey", "Rose"]
i = 2
print( geographers[ (i-3)**2-4:-1 ] )

See if you can work out in your head before typing it!

Finding Things in Lists

Where’s Wally?

list.index(...) tells you where something can be found in a list:

geographers = ["Massey", "Harvey", "Rose"]
geographers.index("Harvey") # 1
geographers.index("Massey") # 0

Combining ideas that will become very useful later:

print(geographers[ geographers.index("Massey") ])

What do you think this prints? Why does it work at all?

Where’s Wally (Part 2)

list.index(...) has one flaw:

geographers = ["Massey", "Harvey", "Rose"]
geographers.index('Batty')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: 'Batty' is not in list

If ‘throwing an error’ is overkill, then here’s another way:

if 'Batty' in geographers:
    print("Found Mike!")
else:
    print("Not a geographer!")

Sorting

We can sort lists in alpha-numerical order:

geographers = ["Massey", "Harvey", "Rose"]
geographers.sort()
print(geographers) # ['Harvey', 'Massey', 'Rose']

And we can reverse-sort too:

geographers.sort(reverse=True)
print(geographers) # ['Rose', 'Massey', 'Harvey']

Changing Lists

Lists are Mutable

Mutable == “liable or subject to change or alteration”

Let’s replace Rose with Jefferson1 in the list.

geographers = ["Massey", "Harvey", "Rose"]
geographers[2] = "Jefferson"
print(geographers) # ['Massey','Harvey','Jefferson']

Adding/Removing Items

When we insert() items into, or pop() items out of, a list we normally need to specify the index.

geographers = ["Massey", "Harvey", "Jefferson"]
geographers.insert(0,"von Humboldt")
print(geographers) 
# ['von Humboldt', 'Massey', 'Harvey', 'Jefferson']
geographers.insert(3,"von Humboldt")
print(geographers) 
# ['von Humboldt', 'Massey', 'Harvey', 'von Humboldt', 'Jefferson']

And in ‘reverse’:

geographers.pop(3) # 'von Humboldt'
print(geographers) 
# ['von Humboldt', 'Massey', 'Harvey', 'Jefferson']

Test Yourself

There are two ways to remove David Harvey from the list of geographers without writing this:

geographers = ['von Humboldt', 'Massey', 'Harvey', 'Jefferson']
geographers.pop(2) # Do not use this answer!
  1. You can adapt an example we saw earlier in ‘Finding Things’.
  2. You can use Google to see if there are list operations we’ve not covered.

Combining Lists

Concatenating

We combine lists using addition:

female_geographers = ['Rose','Valentine','Massey','Jefferson']
male_geographers = ['Von Humboldt','Harvey','Hägerstrand']
all_geographers = female_geographers + male_geographers
print(all_geographers)    # ['Rose', ..., 'Hägerstrand']
print(all_geographers[0]) # Rose

Appending

Note that this is not the same!

female_geographers = ['Rose','Valentine','Massey','Jefferson']
male_geographers   = ['Von Humboldt','Harvey','Hägerstrand']
all_geographers = []
all_geographers.append(female_geographers)
 all_geographers.append(male_geographers)
print(all_geographers) # [['Rose',...], [..., 'Hägerstrand']]
print(all_geographers[0]) # ['Rose', ..., 'Jefferson']

What do you think has happened here?

Test Yourself

male_geographers = ['Von Humboldt','Harvey','Hägerstrand']
male_geographers.append('Batty')
print(male_geographers)

What do you think this will produce? And why do you think that append appears to do something different in these two examples?

Finally…

How many geographers do I know?

len(...) gives you the length of ‘countable’ things:

geographers = ["Massey","Harvey","Rose"]
len(geographers) # 3

But…

female_geographers = ['Rose','Valentine','Massey','Jefferson']
male_geographers = ['Von Humboldt','Harvey','Hägerstrand']
all_geographers = []
all_geographers.append(female_geographers)
all_geographers.append(male_geographers)
print( len(all_geographers) ) # 2

Who’s on the List?

geographers = ["Massey","Harvey","Rose"]
print("Massey" in geographers) # True
print("Batty" in geographers)  # False

But…

geographers.index('Batty')

is a ValueError that causes your Python code to fail.

Why might you choose one of these over the other?

Test Yourself

How would you change this code:

geographers = ["Massey","Harvey","Rose"]
print("Massey" in geographers)
print("Batty" in geographers)

So that it prints:

False
True

You will have seen the answer to this in Code Camp, but you can also Google it!

Tuples: Not Actually a List

Because they come up a lot in geo-data, it’s worth knowing about tuples, which are basically immutable lists:

t = (52.124021, -0.0012012)
print(type(t)) # <class 'tuple'>
print(t)       # (52.124021, -0.0012012)
print(t[0])    # 52.124021

But this…

t[0] = 25.1203210

will throw an error:

TypeError: ‘tuple’ object does not support item assignment

Resources