Comprehensions

INPUT · Slides

Unpicking a nested list

01 / 07

A list inside a list

Table-shaped data is often held as a list with lists inside it — one list per row.

You frequently want to turn that into a single flat list. With for that means looping twice and calling append.

table = [[1, 2], [3, 4]]flat = []for row in table:    for x in row:        flat.append(x)print(flat)

Result

[1, 2, 3, 4]

02 / 07

Two fors side by side

In a comprehension you simply write two fors one after the other.

[x for row in table for x in row] and you already have the flat list.

table = [[1, 2], [3, 4]]print([x for row in table for x in row])

Result

[1, 2, 3, 4]

03 / 07

Write them outermost first

This is the easiest part to get wrong. The fors go in order from the outside in.

Top to bottom in the for statement version becomes left to right in the comprehension, unchanged.

for row in table:      →  for row in table    for x in row:      →  for x in row

Only the expression moves to the front; everything else is in exactly the same order. Swap them round and you use row before it exists, which gets you a NameError.

table = [["red", "blue"], ["yellow"]]print([c for row in table for c in row])

Result

['red', 'blue', 'yellow']

04 / 07

You can add an if

The if from the last lesson goes right at the end.

Flattening and filtering in a single line. Bear in mind that this is where it starts to get hard to read, so think before you reach for it.

table = [[1, 2], [3, 4]]print([x for row in table for x in row if x % 2 == 0])

Result

[2, 4]

05 / 07

Making every combination

Two fors are not only for flattening. They also make every combination.

Loop over two separate lists and the inner one goes all the way round for every step of the outer one. You end up with as many items as the two counts multiplied together.

sizes = ["S", "M"]colours = ["red", "blue"]print([f"{s} in {c}" for s in sizes for c in colours])

Result

['S in red', 'S in blue', 'M in red', 'M in blue']

06 / 07

Square brackets inside keep the rows

Sometimes you want a list of lists, not a flat one. For that you wrap the inner part in square brackets again.

The result is a completely different shape from two fors side by side. The only difference on the page is a pair of brackets, so read carefully.

print([[x * y for y in range(1, 4)] for x in range(1, 4)])

Result

[[1, 2, 3], [2, 4, 6], [3, 6, 9]]

07 / 07

Pack too much in and it stops being readable

Now that you are this far, a warning worth writing down.

A comprehension is short, but pack too much in and it stops being readable. Three levels of nesting with two ifs is kinder written out as an ordinary for.

Shortness is not the goal. Readability is the goal, and most of the time a comprehension serves it — please keep them in that order. When in doubt, go back to for. That is not a defeat.

From the next lesson we start swapping the brackets for other punctuation.