Skip to content
On this page

List Comprehensions

List comprehensions are a built-in feature in Python that provide a simple yet powerful way to create lists.

For example, to generate a list of numbers from 1 to 10, you can use list(range(1, 11)):

python
>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

However, if you want to generate the list ([1 \times 1, 2 \times 2, 3 \times 3, \ldots, 10 \times 10]), the first method is to use a loop:

python
>>> L = []
>>> for x in range(1, 11):
...     L.append(x * x)
...
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

But using a loop can be cumbersome. Instead, you can use a list comprehension to achieve the same result in a single line:

python
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

In the list comprehension, you place the element to be generated (x * x) at the front, followed by the for loop, allowing you to create the list efficiently. The more you practice, the more comfortable you'll become with this syntax.

You can also add an if condition to filter results. For example, to get only the squares of even numbers:

python
>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

You can use multiple for loops to generate combinations or permutations:

python
>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

Using three or more nested loops in comprehensions is rare.

With list comprehensions, you can write very concise code. For instance, to list all files and directories in the current directory, you can do it in one line:

python
>>> import os  # We'll discuss modules later
>>> [d for d in os.listdir('.')]  # os.listdir lists files and directories
['.emacs.d', '.ssh', '.Trash', 'Adlm', 'Applications', 'Desktop', 'Documents', 'Downloads', 'Library', 'Movies', 'Music', 'Pictures', 'Public', 'VirtualBox VMs', 'Workspace', 'XCode']

You can also use multiple variables in a for loop. For instance, using dict.items() lets you iterate over both keys and values:

python
>>> d = {'x': 'A', 'y': 'B', 'z': 'C'}
>>> for k, v in d.items():
...     print(k, '=', v)
...
y = B
x = A
z = C

Thus, you can also use two variables in list comprehensions:

python
>>> d = {'x': 'A', 'y': 'B', 'z': 'C'}
>>> [k + '=' + v for k, v in d.items()]
['y=B', 'x=A', 'z=C']

You can convert all strings in a list to lowercase as follows:

python
>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']

Using if...else in List Comprehensions

Many people get confused about how to use if...else in list comprehensions.

For instance, the following code outputs only even numbers:

python
>>> [x for x in range(1, 11) if x % 2 == 0]
[2, 4, 6, 8, 10]

However, you cannot add an else statement after the last if:

python
>>> [x for x in range(1, 11) if x % 2 == 0 else 0]
  File "<stdin>", line 1
    [x for x in range(1, 11) if x % 2 == 0 else 0]
                                              ^
SyntaxError: invalid syntax

This is because the if following for is a filter condition and cannot have an else; otherwise, how would you filter?

Some might find that placing if before for must be accompanied by else, or it will raise an error:

python
>>> [x if x % 2 == 0 for x in range(1, 11)]
  File "<stdin>", line 1
    [x if x % 2 == 0 for x in range(1, 11)]
                       ^
SyntaxError: invalid syntax

This is because the part before for must evaluate to an expression based on x. Thus, the expression x if x % 2 == 0 cannot be evaluated because it lacks an else. It must be:

python
>>> [x if x % 2 == 0 else -x for x in range(1, 11)]
[-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]

Here, x if x % 2 == 0 else -x produces a definite result based on the value of x.

In summary, in a list comprehension, the if...else part before for is an expression, while the if after for is a filtering condition and should not contain else.

Exercise

If a list contains both strings and integers, the list comprehension will raise an error because non-string types do not have a lower() method:

python
>>> L = ['Hello', 'World', 18, 'Apple', None]
>>> [s.lower() for s in L]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <listcomp>
AttributeError: 'int' object has no attribute 'lower'

You can use the built-in isinstance function to check if a variable is a string:

python
>>> x = 'abc'
>>> y = 123
>>> isinstance(x, str)
True
>>> isinstance(y, str)
False

Please modify the list comprehension by adding an if statement to ensure it executes correctly:

python
L1 = ['Hello', 'World', 18, 'Apple', None]
L2 = ???

# Test:
print(L2)
if L2 == ['hello', 'world', 'apple']:
    print('Test passed!')
else:
    print('Test failed!')

Summary

Using list comprehensions allows for quick generation of lists and enables you to derive one list from another in a very concise manner.

List Comprehensions has loaded