runtime
65 / 250
lesson 65 Comprehensions · intermediate

Filter in a comprehension, or use a loop

An `if` at the end of a comprehension keeps only the items that pass. Knowing when a plain loop reads better is part of using comprehensions well.

You'll be able to
  • Filter with [value for item in items if test], in lists, dictionaries and sets
  • Tell the filter if at the end from the conditional expression in front
  • Choose a loop for side effects, early exits and running state
The idea

The the Collection Algorithms module filter loop had an if around the append. In a comprehension the same test goes at the end: [value for item in items if test]. Items that fail the test produce nothing, so the result can be shorter than the input. The same clause works in dictionary and set comprehensions.

Run each example to see what it prints. Running examples doesn't count toward progress.

example-1.py · Flights that arrived late
flights = [
    {"flight": "UA2017", "arrival_delay": -4},
    {"flight": "MQ3443", "arrival_delay": 12},
    {"flight": "MQ3615", "arrival_delay": 42},
    {"flight": "DL1270", "arrival_delay": -25},
    {"flight": "AA1214", "arrival_delay": 16},
]
late = [f["flight"] for f in flights if f["arrival_delay"] >= 15]
print(late)
delays = {f["flight"]: f["arrival_delay"] for f in flights if f["arrival_delay"] >= 15}
print(delays)

Two ifs can appear in a comprehension and they do different jobs. A conditional expression in front (“Build a list with a comprehension”) chooses a value, and every item still produces one. An if at the end decides whether the item produces anything at all.

example-2.py · Choose or drop
delays = [-4, 12, 42, -25, 16]
early_as_zero = [d if d > 0 else 0 for d in delays]
only_late = [d for d in delays if d > 0]
print(early_as_zero)
print(only_late)
example-3.py · An else on the filter
delays = [-4, 12, 42]
late = [d for d in delays if d > 0 else 0]
print(late)

An if may also follow the first for of a two-clause comprehension, to skip whole groups before the inner loop runs: [sku for o in orders if o["paid"] for sku in o["skus"]].

When a loop is clearer. A comprehension says *build this collection*. Use a plain for loop when the job is something else:

  • side effects: printing, writing a file, appending to another list;
  • stopping early: break at the first match;
  • state that carries over: a running balance or a previous value, because each item of a comprehension is computed on its own;
  • several steps per item: if the expression needs three method calls and two conditions, give the steps names in a loop.

A good rule: one transform and one filter fit in a comprehension; more than that belongs in a loop or a helper function.

Review
  • [value for item in items if test] keeps only items that pass; the result can be shorter than the input.
  • In front, a if test else b chooses a value; at the end, if test filters. A filter has no else.
  • Use a loop for printing, stopping early, running totals, and anything that needs several named steps.
  • Next module: built-in functions such as zip, sorted with a key, any, all, sum, min and max.
Practise this

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

Filter in a comprehension, or use a loop — Comprehensions · Runtime