Picking items with if
Sometimes the new list should have only some of the items. With a loop you'd put an if inside it:
scores = [72, 45, 90, 38, 66]
passed = []
for score in scores:
if score >= 50:
passed.append(score)
print(passed)
[72, 90, 66]A list comprehension can do the same. The condition goes at the end:
scores = [72, 45, 90, 38, 66]
passed = [score for score in scores if score >= 50]
print(passed)
[72, 90, 66]The shape is now:
[expression for item in series if condition]
Only the items for which the condition is True make it into the new list. The others are skipped, so the new list can be shorter than the original, or even empty. This is called filtering. Here the expression is just score, so the items that pass go in as they are.
Filter and change at the same time
The expression can still change the items that pass the filter:
>>> numbers = [3, 8, 5, 12, 7, 4]
>>> [n for n in numbers if n % 2 == 0]
[8, 12, 4]
>>> [n * n for n in numbers if n % 2 == 0]
[64, 144, 16]
>>> [n for n in numbers if n > 100]
[]In the second comprehension, 3, 5 and 7 are never squared at all. They're left out before the expression is worked out.
A filter as a guard
That order matters when the expression can fail. Here each team shares 40 pizza slices, and the comprehension works out how many slices each person gets. But two teams have 0 people, a mistake in the data, and dividing by 0 stops the program:
team_sizes = [4, 0, 5, 0, 10]
pizza_slices = [40 // size for size in team_sizes]
print(pizza_slices)
Traceback (most recent call last):
File "main.py", line 2, in <module>
pizza_slices = [40 // size for size in team_sizes]
~~~^^~~~~~
ZeroDivisionError: division by zeroA filter fixes it. For each size, Python checks the condition first, and only a size that passes gets as far as 40 // size:
team_sizes = [4, 0, 5, 0, 10]
pizza_slices = [40 // size for size in team_sizes if size != 0]
print(pizza_slices)
[10, 8, 4]The condition can be anything that gives True or False, including conditions joined with and and or, and in:
>>> words = ["apple", "fig", "banana", "kiwi", "cherry"]
>>> [w for w in words if len(w) > 3 and "a" in w]
['apple', 'banana']