Warm-up · Activity 1 of 7
// B4.1 · ~25 min · Beginner
List methods, stacks and queues
After this lesson you can change a list with its methods, choose between sort() and sorted(), and use a list as a stack and a deque as a queue.
Lesson 1 of 6 in B4 Data structures
You will be able to
- Change a list with append, extend, insert, remove and pop, and search it with index and count
- Choose between list.sort(), which sorts in place, and sorted(), which returns a new list
- Use a list as a stack and collections.deque as a queue
Predict · Activity 2 of 7
Predict before you read on: what does this print?
a = [1, 2] a.append([3, 4]) b = [1, 2] b.extend([3, 4]) print(len(a), len(b))Practice · Activity 3 of 7
Fill in the method that removes the last item and gives it back, so top is 3 and stack is [1, 2].
stack = [1, 2, 3] top = stack.____()top = stack.()Practice · Activity 4 of 7
What does this print?
nums = [3, 1, 2] result = nums.sort() print(result, nums)Practice · Activity 5 of 7
Each call starts from its own nums = [5, 2, 7, 2]. Match the call to what it does.
nums = [5, 2, 7, 2]Brain teaser · Activity 6 of 7
Brain teaser. A deque can add and remove at both ends. What does this print?
from collections import deque line = deque(["ana", "ben"]) line.append("cleo") line.appendleft("dan") print(line.popleft(), line.pop())Apply · Activity 7 of 7
Mini-task. Write balanced(text), which returns True when every bracket ( [ { in text is closed by the matching ) ] } in the right order. Use a list as a stack: push each opening bracket, and pop when a closing one arrives. Try "(a[b]{c})", "(]", "(()" and "x)".
Check your work against this list
Build it yourself
Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.
Worked example
A print queue and an undo stack
An editor keeps two collections. Print jobs wait in a deque and are printed in the order they arrived. Edits go on a list, and undo takes the newest one back first. At the end the program sorts a list of page counts twice: once into a new list with sorted(), once in place with sort(). Run it, then add a job or an edit and run it again.
main.py
from collections import deque
# Print jobs are served in the order they arrive: a queue.
jobs: deque[str] = deque()
jobs.append("report.pdf")
jobs.append("photo.png")
jobs.append("invoice.pdf")
# Edits are undone newest first: a stack.
edits: list[str] = []
edits.append("type 'Hello'")
edits.append("make bold")
edits.append("delete line 3")
print("Printing:", jobs.popleft())
print("Next up:", jobs[0])
print("Undo:", edits.pop())
print("Undo:", edits.pop())
print("Edits left:", edits)
pages = [12, 3, 7]
print("Sorted copy:", sorted(pages), "original:", pages)
pages.sort(reverse=True)
print("Sorted in place:", pages)
Run it with
python main.pyOutput
Printing: report.pdf
Next up: photo.png
Undo: delete line 3
Undo: make bold
Edits left: ["type 'Hello'"]
Sorted copy: [3, 7, 12] original: [12, 3, 7]
Sorted in place: [12, 7, 3]- popleft() takes the oldest job, and jobs[0] shows the next one without removing it.
- pop() takes the newest edit, so the edits come back in reverse order.
- sorted(pages) left pages as it was; pages.sort(reverse=True) changed it.
Change it and run it
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.
Exercises
Exercise 1 of 2
Top three without side effects
top_three(scores) should return the three highest scores, highest first. The starter gets the right answer, but it also reorders the list the caller passed in. Fix it so the caller’s list stays exactly as it was.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.
Hints
Hint 1
scores.sort() changes the caller’s list, because the function gets the same list object, not a copy.
Hint 2
sorted() returns a new list and leaves its argument alone.
Hint 3
return sorted(scores, reverse=True)[:3]
Show a solution
One way to solve it. Yours can look different and still pass the checks.
def top_three(scores: list[int]) -> list[int]:
"""Return the three highest scores, highest first."""
return sorted(scores, reverse=True)[:3]
Run it on your computer
Install Python 3.14 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.py
def top_three(scores: list[int]) -> list[int]:
"""Return the three highest scores, highest first."""
scores.sort(reverse=True)
return scores[:3]
test_main.py
from main import top_three
def test_highest_first():
"""Returns the three highest scores, highest first"""
got = top_three([40, 90, 10, 70, 55])
assert got == [90, 70, 55], f"top_three([40, 90, 10, 70, 55]) returned {got!r}, expected [90, 70, 55]"
def test_list_unchanged():
"""Leaves the caller's list in its original order"""
scores = [40, 90, 10, 70, 55]
top_three(scores)
assert scores == [40, 90, 10, 70, 55], f"after the call the caller's list is {scores!r}; it must not change"
def test_short_list():
"""Works with fewer than three scores"""
got = top_three([5, 8])
assert got == [8, 5], f"top_three([5, 8]) returned {got!r}, expected [8, 5]"
On macOS and Linux, type python3 wherever these commands say python, as in the first lesson.
Run the program:
python main.pyRun the checks (needs learnrun.py in the same folder):
python learnrun.py testDownload learnrun.pyExercise 2 of 2
A fair queue
serve_all(commands) runs a list of commands. "join ana" puts ana in the queue; "serve" serves whoever has waited longest and records the name, or records "nobody" when the queue is empty. Return the recorded names in order. The starter serves the newest person instead and crashes on an empty queue. Use collections.deque.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.
Hints
Hint 1
waiting.pop() takes the newest name. A queue must take the oldest, from the front.
Hint 2
from collections import deque, then waiting = deque() and waiting.popleft().
Hint 3
Check if waiting: before popleft(); an empty deque is false.
Show a solution
One way to solve it. Yours can look different and still pass the checks.
from collections import deque
def serve_all(commands: list[str]) -> list[str]:
"""Run join and serve commands; return who was served, in order."""
waiting: deque[str] = deque()
served = []
for command in commands:
if command.startswith("join "):
waiting.append(command[5:])
elif command == "serve":
if waiting:
served.append(waiting.popleft())
else:
served.append("nobody")
return served
Run it on your computer
Install Python 3.14 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.py
def serve_all(commands: list[str]) -> list[str]:
"""Run join and serve commands; return who was served, in order."""
waiting = []
served = []
for command in commands:
if command.startswith("join "):
waiting.append(command[5:])
elif command == "serve":
# Serve the person who has waited longest,
# or record "nobody" when no one is waiting.
served.append(waiting.pop())
return served
test_main.py
from main import serve_all
def test_first_come_first_served():
"""Serves people in the order they joined"""
got = serve_all(["join ana", "join ben", "serve", "join cleo", "serve", "serve"])
assert got == ["ana", "ben", "cleo"], f"served {got!r}, expected ['ana', 'ben', 'cleo']"
def test_nobody_waiting():
"""Records nobody when the queue is empty"""
got = serve_all(["serve", "join ana", "serve", "serve"])
assert got == ["nobody", "ana", "nobody"], f"served {got!r}, expected ['nobody', 'ana', 'nobody']"
def test_no_commands():
"""Serves no one when there are no commands"""
got = serve_all([])
assert got == [], f"serve_all([]) returned {got!r}, expected []"
On macOS and Linux, type python3 wherever these commands say python, as in the first lesson.
Run the program:
python main.pyRun the checks (needs learnrun.py in the same folder):
python learnrun.py testDownload learnrun.pyCommon mistakes
Keeping the result of sort()
scores = [30, 10, 20]
scores = scores.sort()
print(scores[0])
What Python prints
TypeError: 'NoneType' object is not subscriptableWhy, and the fix
sort() sorts the list in place and returns None, so scores = scores.sort() throws the list away and keeps None. Call scores.sort() on its own line, or write scores = sorted(scores) when you want a new list.
Removing a value that is not there
guests = ["ana", "ben"]
guests.remove("zoe")
What Python prints
ValueError: list.remove(x): x not in listWhy, and the fix
remove raises ValueError when no item equals the value. Check first with if "zoe" in guests: guests.remove("zoe"). index behaves the same way for a missing value.
Popping from an empty stack
undo = []
last = undo.pop()
What Python prints
IndexError: pop from empty listWhy, and the fix
An empty list has nothing to pop. Guard the call with if undo: … because an empty list is false. A deque raises IndexError too, with the message "pop from an empty deque".
Python in the browser: Pyodide 314.0.7, MPL-2.0. Licence and source
Exit ticket
5 questions, no hints. Score 80% or more to complete the lesson.
Finish every activity above to unlock the exit ticket.