Foundations introduced list comprehensions for transforms. Today: the if clause, which lets the comprehension also filter.
numbers = [1, 2, 3, 4, 5, 6]
# All squared:
[n * n for n in numbers] # [1, 4, 9, 16, 25, 36]
# Only even, squared:
[n * n for n in numbers if n % 2 == 0] # [4, 16, 36]The if goes at the end. It's a filter, not a branch.
Right — items that fail the if are dropped, not transformed into something else. There's no else in the filter position.
What if I do want a branch — keep all items but transform them differently?
Then the conditional moves into the expression part, and you use a Python ternary x if cond else y:
[n if n > 0 else 0 for n in numbers] # negative numbers replaced with 0This is not a filter — the comprehension always emits one item per input. It's a transform that branches.
Two different shapes. Filter at the end vs ternary in the expression.
And don't combine them on the same line until you've written each shape a few times. [transform(n) if cond1 else other(n) for n in xs if cond2] is legal, readable, and should be a regular for loop.
if at the end[expr for x in iterable if condition]Reads: "a list of expr for each x in iterable, only if condition."
numbers = [1, 2, 3, 4, 5, 6]
[n for n in numbers if n % 2 == 0] # [2, 4, 6]
[n * 10 for n in numbers if n > 3] # [40, 50, 60]Items that fail the condition are dropped — the result list is shorter than the input.
A different shape entirely:
[expr1 if cond else expr2 for x in iterable]The ternary expr1 if cond else expr2 is a single expression that evaluates to either expr1 or expr2. Output length equals input length.
numbers = [-2, -1, 0, 1, 2]
[n if n > 0 else 0 for n in numbers] # [0, 0, 0, 1, 2]The negative numbers are replaced with 0, not removed.
Legal, but cognitive load is high:
[n * 10 if n > 0 else 0 for n in numbers if n != 0]Reads: "For each n not equal to zero, emit n * 10 if positive else 0." Even reading carefully, you reach for a regular for-loop. Don't write this for the sake of one-line bragging rights.
Any iterable works.
[c for c in "hello" if c in "aeiou"] # ['e', 'o']
[i for i in range(10) if i % 3 == 0] # [0, 3, 6, 9]for with side effects[print(n) for n in numbers if n > 0] # works, but builds a list of NoneIf you don't care about the result, use a for loop:
for n in numbers:
if n > 0:
print(n)[expr for x in xs][expr for x in xs if cond][a if cond else b for x in xs][a if cond1 else b for x in xs if cond2] — pause; consider a regular loopFoundations introduced list comprehensions for transforms. Today: the if clause, which lets the comprehension also filter.
numbers = [1, 2, 3, 4, 5, 6]
# All squared:
[n * n for n in numbers] # [1, 4, 9, 16, 25, 36]
# Only even, squared:
[n * n for n in numbers if n % 2 == 0] # [4, 16, 36]The if goes at the end. It's a filter, not a branch.
Right — items that fail the if are dropped, not transformed into something else. There's no else in the filter position.
What if I do want a branch — keep all items but transform them differently?
Then the conditional moves into the expression part, and you use a Python ternary x if cond else y:
[n if n > 0 else 0 for n in numbers] # negative numbers replaced with 0This is not a filter — the comprehension always emits one item per input. It's a transform that branches.
Two different shapes. Filter at the end vs ternary in the expression.
And don't combine them on the same line until you've written each shape a few times. [transform(n) if cond1 else other(n) for n in xs if cond2] is legal, readable, and should be a regular for loop.
if at the end[expr for x in iterable if condition]Reads: "a list of expr for each x in iterable, only if condition."
numbers = [1, 2, 3, 4, 5, 6]
[n for n in numbers if n % 2 == 0] # [2, 4, 6]
[n * 10 for n in numbers if n > 3] # [40, 50, 60]Items that fail the condition are dropped — the result list is shorter than the input.
A different shape entirely:
[expr1 if cond else expr2 for x in iterable]The ternary expr1 if cond else expr2 is a single expression that evaluates to either expr1 or expr2. Output length equals input length.
numbers = [-2, -1, 0, 1, 2]
[n if n > 0 else 0 for n in numbers] # [0, 0, 0, 1, 2]The negative numbers are replaced with 0, not removed.
Legal, but cognitive load is high:
[n * 10 if n > 0 else 0 for n in numbers if n != 0]Reads: "For each n not equal to zero, emit n * 10 if positive else 0." Even reading carefully, you reach for a regular for-loop. Don't write this for the sake of one-line bragging rights.
Any iterable works.
[c for c in "hello" if c in "aeiou"] # ['e', 'o']
[i for i in range(10) if i % 3 == 0] # [0, 3, 6, 9]for with side effects[print(n) for n in numbers if n > 0] # works, but builds a list of NoneIf you don't care about the result, use a for loop:
for n in numbers:
if n > 0:
print(n)[expr for x in xs][expr for x in xs if cond][a if cond else b for x in xs][a if cond1 else b for x in xs if cond2] — pause; consider a regular loopCreate a free account to get started. Paid plans unlock all tracks.