Chapter 3 · Data
Comprehensions and sorting
Step 1 of 22 · Concept
A comprehension builds a list
In this lesson you build lists in one line, and sort them by any key you choose.
This loop builds a list:
doubled = []
for x in nums:
doubled.append(x * 2)
A comprehension writes that loop in one line:
doubled = [x * 2 for x in nums]
With nums = [1, 2, 3], both give [2, 4, 6].
Step 2 of 22 · Quiz
Predict the list
Type exactly what this program prints.
squares = [n * n for n in range(5)]
print(squares)
print(len(squares), squares[-1])
Step 3 of 22 · Demo
See it run
Run it and compare with your answer. Then change n * n to n + 1 and run it again.
Step 4 of 22 · Demo
Keep only some
An if at the end keeps only the items for which it is True.
Run it: only the words of more than 3 letters stay.
Step 5 of 22 · Exercise
Your turn: one line
- Write
passedas one comprehension instead of the loop. It still prints the same list. - Add
retry: each score under 50, plus 10, with one comprehension. Print it.
The output must be exactly:
[72, 90, 66]
[55, 48]
In a comprehension the value to add comes first, then the for, then the if.
passed is [s for s in scores if ...] with the loop's question. In retry, the value at the front is s + 10.
passed = [s for s in scores if s >= 50]
Step 6 of 22 · Concept
Dictionary and set comprehensions
Curly brackets build a dictionary or a set the same way.
lengths = {w: len(w) for w in words}
sizes = {len(w) for w in words}
- With
key: valueat the front, you get a dictionary: each word with its length. - With one value at the front, you get a set: each length once.
Step 7 of 22 · Demo
Both at work
Run it. "star" and "moon" have the same length, so the set holds 4 once.
Step 8 of 22 · Concept
sum, any and all take a loop directly
sum, any and all take the loop of a comprehension without its square brackets. That loop is a generator
expression.
| write | gives |
|---|---|
sum(x * x for x in nums) | the total of the squares |
any(s < 50 for s in scores) | True when at least one is True |
all(s >= 50 for s in scores) | True when every one is True |
An if works here too: sum(s for s in scores if s >= 50) adds only the passing scores.
Step 9 of 22 · Quiz
Predict the checks
Type exactly what this program prints.
scores = [72, 45, 90]
print(any(s < 50 for s in scores))
print(all(s < 100 for s in scores))
print(sum(s for s in scores if s >= 50))
print(any(s == 100 for s in scores))
Step 10 of 22 · Demo
See it run
Run it and compare with your answer.
Step 11 of 22 · Exercise
Your turn: all passed?
A score passes at 50 or more.
- Print whether all the scores passed.
- Print whether any score is 100.
- Print the total of the passing scores.
The output must be exactly:
All passed: False
Full marks: True
Passing total: 236
Each line is one call: all, any or sum, around a loop without square brackets. No list, no append.
all asks s >= 50 of every score, any asks s == 100. sum takes the score itself, with an if at the end.
print("Passing total:", sum(s for s in scores if s >= 50))
Step 12 of 22 · Concept
sorted makes a new list; sort changes this one
sorted(xs)makes a new list, in order.xsstays as it was.zs.sort()puts the listzsitself in order, and returnsNone.
Step 13 of 22 · Quiz
Predict the lists
Type exactly what this program prints.
xs = [3, 1, 2]
ys = sorted(xs)
zs = [3, 1, 2]
zs.sort()
print(xs, ys, zs)
ws = [3, 1, 2]
ws = ws.sort()
print(ws)
print(sorted(["bob", "Cy", "ann"]))
Step 14 of 22 · Demo
See it run
Run it and compare with your answer.
Step 15 of 22 · Concept
sorted can sort by a key
words = ["kiwi", "fig", "banana", "pear"]
print(sorted(words, key=len))
This prints ['fig', 'kiwi', 'pear', 'banana']: shortest first.
- A function is a value, as
defmakes it (lesson 7).key=lenpasses the function itself: no brackets. sortedcalls it on each item, and sorts the items by what it returns.- Equal keys keep their order:
"kiwi"and"pear"both have 4 letters, and"kiwi"came first.
Step 16 of 22 · Concept
lambda: a function in one line
ranked = sorted(pairs, key=lambda p: p[1], reverse=True)
lambda p: p[1]is a function with no name: it returnsp[1], the item at index 1, the score.reverse=Trueputs the highest keys first.max(pairs, key=lambda p: p[1])gives the pair with the highest score.minworks the same way.
Step 17 of 22 · Quiz
Predict the ranking
Type exactly what this program prints.
pairs = [("Ada", 72), ("Bo", 95), ("Cy", 88)]
ranked = sorted(pairs, key=lambda p: p[1], reverse=True)
print(ranked)
best = max(pairs, key=lambda p: p[1])
print(best[0])
words = ["kiwi", "fig", "banana", "pear"]
print(sorted(words, key=len))
Step 18 of 22 · Demo
See it run
Run it and compare with your answer. Then take reverse=True out, and run it again.
Step 19 of 22 · Exercise
Your turn: a leaderboard
- Sort
scoresby score, highest first. - Print the top 3, numbered from 1, each with its name and score.
The output must be exactly:
1. Bo 95
2. Ed 91
3. Cy 88
Sort as the ranking did. The top 3 are a slice of the sorted list.
ranked[:3] is the top 3. enumerate(..., start=1) numbers them from 1 (lesson 11).
for i, p in enumerate(ranked[:3], start=1):
Step 20 of 22 · Check yourself
Check yourself: word statistics
- Make
lengths, a dictionary of each word and its length, and print it. - Print the words of 5 letters or more, in alphabetical order.
- Print the longest word.
The output must be exactly:
{'sky': 3, 'planet': 6, 'sun': 3, 'comet': 5, 'moon': 4}
['comet', 'planet']
Longest: planet
Each item of the plan is one line of work: a comprehension, or one call with a key.
Step 21 of 22 · Challenge · optional
Challenge: sort by two keys
Optional.
Print the pairs by score, highest first. When two scores are equal, the names go in alphabetical order. The output must be exactly:
Ada 95
Di 95
Bo 88
Cy 88
Tuples compare item by item: the first items first, and the second items only when the first are equal.
Make the key a tuple: the score, then the name. -p[1] puts the higher scores first, so you need no reverse.
ranked = sorted(pairs, key=lambda p: (-p[1], p[0]))
Step 22 of 22 · Recap
Recap
[n * n for n in range(5)]builds a list; anifat the end keeps only some.{w: len(w) for w in words}builds a dictionary,{len(w) for w in words}a set.sum,anyandalltake a loop directly:any(s < 50 for s in scores).sorted(xs)makes a new list;xs.sort()changesxsand returnsNone.key=lenorkey=lambda p: p[1]sorts by a key.
Next: lesson 14 solves a problem with a smaller copy of itself: recursion.
Review
4 questions from this lesson, in a new order each time. Answer from memory: 3 of 4 right on the first try passes. On a day after you finish the lesson, a pass earns 15 XP.
The review needs JavaScript.
squares = [n * n for n in range(5)]
print(squares)
print(len(squares), squares[-1])
words = ["a", "tree", "is", "green"]
long = [w for w in words if len(w) > 3]
print(long)
scores = [72, 45, 90, 38, 66]
passed = []
for s in scores:
if s >= 50:
passed.append(s)
print(passed)
# retry: each score under 50, plus 10
words = ["sun", "moon", "star", "sky"]
lengths = {w: len(w) for w in words}
print(lengths)
sizes = {len(w) for w in words}
print(sorted(sizes))
scores = [72, 45, 90]
print(any(s < 50 for s in scores))
print(all(s < 100 for s in scores))
print(sum(s for s in scores if s >= 50))
print(any(s == 100 for s in scores))
scores = [55, 100, 48, 81]
# print the three lines of the task
xs = [3, 1, 2]
ys = sorted(xs)
zs = [3, 1, 2]
zs.sort()
print(xs, ys, zs)
ws = [3, 1, 2]
ws = ws.sort()
print(ws)
print(sorted(["bob", "Cy", "ann"]))
pairs = [("Ada", 72), ("Bo", 95), ("Cy", 88)]
ranked = sorted(pairs, key=lambda p: p[1], reverse=True)
print(ranked)
best = max(pairs, key=lambda p: p[1])
print(best[0])
words = ["kiwi", "fig", "banana", "pear"]
print(sorted(words, key=len))
scores = [("Ada", 72), ("Bo", 95), ("Cy", 88),
("Di", 60), ("Ed", 91)]
# sort by score, highest first; print the top 3
words = ["sky", "planet", "sun", "comet", "moon"]
# the three lines of the task
pairs = [("Cy", 88), ("Ada", 95), ("Bo", 88), ("Di", 95)]
for p in pairs:
print(p[0], p[1])