Appearance
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.