# Python Comprehensions

Python comprehensions are syntactic constructs that enable sequences to be built from other sequences in a clear and concise manner. Python comprehensions are of three types namely:

- list comprehensions,
- set comprehensions and
- dict comprehensions.

List comprehension constructs have been part of python since python 2.0 while set and dict comprehensions have been part of python since python 2.7.

# List Comprehensions

List comprehensions are by far the most popular python comprehension construct. List comprehensions provide a concise way to create new list of elements that satisfy a given condition from an **iterable**. An **iterable** is any python construct that can be looped over. Examples of inbuilt iterables include lists, sets and tuples. The example below from the python documentation illustrates the usage of list comprehensions. In this example, we want to create a list of squares of the numbers from 0 to 10. One conventional way of creating this list without comprehensions is given below :

```
>>> squares = []
>>> for x in range(10):
... squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
```

The same list can be created in a more concise manner using list comprehensions as below:

```
>>> squares = [x**2 for x in range(10)]
```

The comprehension version is obviously clearer and more concise than the conventional method.

According to the python documentation, **a list comprehension consists of square brackets containing an expression followed by a for clause and zero or more for or if clauses as shown below.**

```
[expression for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
...
for itemN in iterableN if conditionN ]
```

The result is a new list resulting from evaluating the expression in the context of the *for* and *if* clauses which follow it. For example to create a list of the squares of even numbers between 0 and 10, the following comprehension is used:

```
>>> even_squares = [i**2 for i in range(10) if i % 2 == 0]
>>> even_squares
[0, 4, 16, 36, 64]
```

The expression `i**2`

is computed in the context of the *for* clause that iterates over the numbers from 0 to 10 and the *if* clause that filters out non-even numbers.

##
Nested *for* loops in List Comprehensions

List comprehensions can also be used with multiple or nested *for* loops. Consider for example, the simple code fragment shown below that creates a tuple from pair of numbers drawn from the two sequences given.

```
>>> combs = []
>>> for x in [1,2,3]:
... for y in [3,1,4]:
... if x != y:
... combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
```

The above can be rewritten in a more concise and simple manner as shown below using list comprehensions

```
>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
```

It is important to take into consideration the order of the *for* loops as used in the list comprehension. Careful observation of the code snippets using comprehension and that without comprehension shows that the order of the *for* loops in the comprehension follows the same order if it had been written without comprehensions. The same applies to nested for loops with nesting depth greater than two.

## Nested List Comprehensions

List comprehensions can also be nested. Consider the following example drawn from the python documentation of a 3x4 matrix implemented as a list of 3 lists of length 4:

```
>>> matrix = [
... [1, 2, 3, 4],
... [5, 6, 7, 8],
... [9, 10, 11, 12],
... ]
```

Transposition is a matrix operation that creates a new matrix from an old one using the rows of the old matrix as the columns of the new matrix and the columns of the old matrix as the rows of the new matrix.

The rows and columns of the matrix can be transposed using the following nested list comprehension:

```
>>> [[row[i] for row in matrix] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
```

The above is equivalent to the snippet given below:

```
>>> transposed = []
>>> for i in range(4):
... transposed.append([row[i] for row in matrix])
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
```

# Set Comprehensions

Set comprehensions were added to python in version 2.7. In set comprehensions, we use the braces rather than

square brackets. For example, to create the set of the squares of all numbers between 0 and 10 the following set comprehensions can be used in lieu of regular looping:

```
>>> x = {i**2 for i in range(10)}
>>> x
set([0, 1, 4, 81, 64, 9, 16, 49, 25, 36])
>>>
```

# Dict Comprehensions

Just like set comprehensions, dict comprehensions were added to python in version 2.7. Below we create a mapping of a number to its square using

dict comprehensions.

```
>>> x = {i:i**2 for i in range(10)}
>>> x
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
```

# Further Reading

- Python Documentation
- Python Essential Reference, Fourth Edition
- Python 3 Patterns, Recipes and Idioms