Lists
Storing many values in order, indexing and slicing them, the methods that change them, and the list comprehension that replaces four lines with one.
Lists
scores = [45, 78, 12, 90, 33]
names = ["Aisha", "Ben", "Chloe"]
mixed = [1, "two", 3.0, True]
empty = []Accessing items
print(scores[0]) # 45, the first
print(scores[-1]) # 33, the last
print(scores[1:4]) # [78, 12, 90], a slice
print(len(scores)) # 5A list of 5 items has indexes 0 to 4. Negative indexes count backwards, so -1 is the last item.
Changing a list
scores[0] = 50 # replace an item
scores.append(60) # add to the end
scores.insert(1, 99) # insert at a position
scores.remove(12) # remove the first occurrence of the value 12
popped = scores.pop() # remove and return the last item
del scores[0] # delete by index
scores.sort() # sort in place
scores.reverse() # reverse in place
scores.clear() # empty itUseful functions
print(sum(scores), max(scores), min(scores), len(scores))
print(sorted(scores)) # a sorted copy, original untouched
print(scores.count(45)) # how many times 45 appears
print(scores.index(78)) # position of the first 78
print(78 in scores) # True or FalseList comprehensions
A compact way to build a list from another list.
squares = [n * n for n in range(1, 6)] # [1, 4, 9, 16, 25]
evens = [n for n in scores if n % 2 == 0] # only the even scores
upper = [name.upper() for name in names] # every name in capitalsThe long form of the first one is:
squares = []
for n in range(1, 6):
squares.append(n * n)Both are correct. Use whichever is clearer for the situation.
- The list holds its items in order, and the first locker is number 0.
- append() puts a new item on the end, so the list grows.
- Assign to an index to replace what is there. The old value is gone.
- scores[2] opens locker 2. len(scores) counts the lockers, so the last index is one less.
- append() adds to the end.
- insert() puts an item at a position, and the rest move along.
- remove() takes out the first item with that value.
- pop() removes the last item and gives it back.
- sort() orders the list in place.
Lists in practice
Reading a list of names and sorting them
names = []
while True:
entry = input("Enter a name, or press enter to finish: ").strip()
if entry == "":
break
names.append(entry.title())
names.sort()
print(f"\n{len(names)} names, in order:")
for i, name in enumerate(names, start=1):
print(f"{i}. {name}")Basic statistics
marks = [67, 82, 45, 91, 58, 73]
marks_sorted = sorted(marks)
middle = len(marks_sorted) // 2
if len(marks_sorted) % 2 == 1:
median = marks_sorted[middle]
else:
median = (marks_sorted[middle - 1] + marks_sorted[middle]) / 2
print(f"Mean: {sum(marks) / len(marks):.1f}")
print(f"Median: {median}")
print(f"Range: {max(marks) - min(marks)}")Key terms you must be able to define
- List
- An ordered collection of values accessed by index, which can be changed.
- Index
- The position of an item in a list or string, counting from 0.
- Slice
- A section of a list or string, taken with a start and end index.
- append
- A list method that adds an item to the end.
- List comprehension
- A compact expression that builds a new list from an existing one.
- Mutable
- Can be changed after creation. Lists are mutable, which is why append works.
- sort
- A list method that reorders the list itself and returns nothing.
- sorted
- A built in function that returns a new sorted list, leaving the original alone.
- enumerate
- A built in function giving both the index and the item while looping.
Flashcards
Say the definition out loud before you flip the card. Retrieving it from memory is what builds recall, reading it again is not.
Reach the top grade on this topic
- Use negative indexes and slices confidently, including
[::-1]to reverse - Know the difference between sort() and sorted(), and choose deliberately
- Use append, insert, remove and del knowing exactly which works by value and which by index
- Know when a list comprehension is clearer than a loop, and when it is not
- Use enumerate rather than a counter variable you maintain by hand
Mistakes that cost marks here
- Using an index equal to the length of the list, which is out of range.
- Using
remove()with an index. It removes by value,delremoves by index. - Forgetting that
sort()changes the list whilesorted()returns a copy. - Expecting
list2 = list1to make a copy. Both names refer to the same list. - Removing items from a list while looping over it, which silently skips entries.
A Python list can hold anything at all, including other lists, and the items do not have to be the same type. That flexibility is why a list is the first structure you reach for, and why a dictionary is sometimes the better one.
Knowledge check
scores[-1] give?scores[1:3] give for [45, 78, 12, 90]?len([4, 8, 15]) give?scores.append(5) do?sort() and sorted()?numbers[::-1] give?remove(3) and del numbers[3]?list2 = list1, what does changing list2 do?[n * 2 for n in [1, 2, 3]] produce?Exam-style questions
Five written questions in the style of the real paper. Write a full answer, then let the marker check it against the mark scheme.
- Lsort() rearranges the original list in place
- Lsorted() returns a new sorted list
- LUse sorted() when the original order must be kept
The sort method rearranges the items of the list it is called on, changing the original list permanently and returning nothing. The sorted function leaves the original list completely untouched and returns a brand new list containing the same items in order. Which one to use depends on whether the original order still matters: if it does, sorted must be used, otherwise the original ordering is lost and cannot be recovered.
- LCreates a list containing the five marks
- LUses max to find the highest
- LUses min to find the lowest
- LUses sum divided by len for the mean
- LPrints all three results
marks = [67, 82, 45, 91, 58] print(f"Highest: {max(marks)}") print(f"Lowest: {min(marks)}") print(f"Mean: {sum(marks) / len(marks):.1f}") The built in functions max, min, sum and len all take the list directly, so no loop is needed at all. The mean is the total divided by how many items there are, and len is used rather than typing 5 so that the program still works correctly if marks are added or removed later.
numbers.remove(3) and del numbers[3].3 marks- Lremove searches for the value 3 and deletes the first match
- Ldel deletes whatever item is at index 3
- LThey affect different items unless the value happens to equal the index
The remove method takes a value rather than a position. It searches the list from the start and deletes the first item equal to that value, raising a ValueError if no item matches. The del statement takes a position and removes whatever item currently sits at that index, raising an IndexError if the index does not exist. For the list [10, 20, 3, 40], remove(3) deletes the value 3 while del numbers[3] deletes 40, so confusing the two silently removes the wrong item.
copy = original and then appends to copy. Explain why original changes as well.3 marks- LAssignment copies the reference, not the list itself
- LBoth names therefore refer to one single list in memory
- LUse copy() or list() to make a genuine copy
Assigning one list to another name does not duplicate the list. It makes the new name refer to exactly the same list already held in memory, so there is only ever one list with two labels attached to it. Appending through either name therefore changes what is seen through both. To create a genuinely separate list the programmer must copy the contents, using original.copy(), list(original) or the slice original[:], each of which builds a new list containing the same items.
numbers[5] on a list containing five items and crashes. Explain why and state the valid range of indexes.3 marks- LList indexes start at 0
- LFive items therefore occupy indexes 0 to 4
- LIndex 5 is out of range so an IndexError occurs
Python lists are indexed from 0, so the first item is at index 0 rather than index 1. A list containing five items therefore occupies indexes 0, 1, 2, 3 and 4, and there is no item at index 5. Attempting to access it raises an IndexError and the program stops. The highest valid index is always the length of the list minus one, which is why loops over a list use range(len(numbers)) rather than range(1, len(numbers) + 1).