# Lesson_04_comprehensions

### Python Training - Lesson 4 - Python 'comprehensions'

Comprehensions are code patterns, or constructs, that allow collections to be built in a short, concise way, from other collections.

• code is shorter and more expressive
• execution of code written as comprehensions is more than 30% - 50% faster

• if you do not follow good readbility rules, such code is hard to understand

#### Types of comprehensions in Python 3

Python 3 comes with built-in comprehension syntax for lists, dictionaries and sets.

## List comprehensions

``````

In [43]:

# Creating a list
s = []

# Filling the list
for element in range(0,10):
s.append(element)

print(s)

``````
``````

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

``````
``````

In [44]:

# Using list comprehension
s = [element for element in range(0,10)]
print(s)

``````
``````

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

``````
``````

In [45]:

# Skip odd numbers
s = [x for x in range(0,10) if x%2 == 0]
print(s)

``````
``````

[0, 2, 4, 6, 8]

``````
``````

In [46]:

# Multiple conditions
s = [x for x in range(0,10) if x%2==0 and x > 4]
print(s)

``````
``````

[6, 8]

``````
``````

In [47]:

# Nested comprehension

# Regular construction
s = []
for x in range(0,10):
for y in range(0,5):
s.append((x,y))
print(s)

``````
``````

[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (5, 0), (5, 1), (5, 2), (5, 3), (5, 4), (6, 0), (6, 1), (6, 2), (6, 3), (6, 4), (7, 0), (7, 1), (7, 2), (7, 3), (7, 4), (8, 0), (8, 1), (8, 2), (8, 3), (8, 4), (9, 0), (9, 1), (9, 2), (9, 3), (9, 4)]

``````
``````

In [48]:

# Nested comprehension - implementation
s = [(x,y) for x in range(0,10) for y in range(0,5)]
print(s)

``````
``````

[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (5, 0), (5, 1), (5, 2), (5, 3), (5, 4), (6, 0), (6, 1), (6, 2), (6, 3), (6, 4), (7, 0), (7, 1), (7, 2), (7, 3), (7, 4), (8, 0), (8, 1), (8, 2), (8, 3), (8, 4), (9, 0), (9, 1), (9, 2), (9, 3), (9, 4)]

``````
``````

In [49]:

# Visually clear formatting for more complicated situation
s = [(x,y) for x in range(0,10)
for y in range(0,5)
if x>3
and y < 4]
print(s)

``````
``````

[(4, 0), (4, 1), (4, 2), (4, 3), (5, 0), (5, 1), (5, 2), (5, 3), (6, 0), (6, 1), (6, 2), (6, 3), (7, 0), (7, 1), (7, 2), (7, 3), (8, 0), (8, 1), (8, 2), (8, 3), (9, 0), (9, 1), (9, 2), (9, 3)]

``````
``````

In [50]:

# Stacking comprehensions
s = [x for x in [y for y in [z for z in range(0,3)]]]
print(s)

``````
``````

[0, 1, 2]

``````
``````

In [51]:

# You can apply all operations that work on lists, as comprehensions work on lists.
s = [x for x in range (0,3)] + [y for y in range(4,5)]
print(s)

``````
``````

[0, 1, 2, 4]

``````
``````

In [52]:

# Practical examples

# Producing cubed numbers for each item in list
l = range(0,15)
cubed = [x**3 for x in l]
print(cubed)

``````
``````

[0, 1, 8, 27, 64, 125, 216, 343, 512, 729, 1000, 1331, 1728, 2197, 2744]

``````

## Dictionary comprehensions

This patterns allow for creating dictionaries using other lists or dictionaries or to transform a dictionary.

``````

In [53]:

# Create dictionary from two lists.

d = {a:b for a,b in zip(['a', 'b', 'c'], range(0,3))}
print(d)

``````
``````

{'a': 0, 'b': 1, 'c': 2}

``````
``````

In [54]:

# Transform dictionary.

transformed = {key: value*2 for (key,value) in d.items()}
print(transformed)

transformed_keys = {key*2: value for (key,value) in d.items()}
print(transformed_keys)

``````
``````

{'a': 0, 'b': 2, 'c': 4}
{'aa': 0, 'bb': 1, 'cc': 2}

``````
``````

In [55]:

# Conditions
d = {a:b for a,b
in zip(['a', 'b', 'c'], range(0,3))
if a != 'c'
and b > 0}
print(d)

``````
``````

{'b': 1}

``````
``````

In [56]:

# Do you have a complex condition using if-else? No problem!

d = {a:(str(b) + " is even"
if b%2==0
else str(b) + " is odd")
for a,b
in zip(['a', 'b', 'c', 'd'], range(0,4))}
print(d)

``````
``````

{'a': '0 is even', 'b': '1 is odd', 'c': '2 is even', 'd': '3 is odd'}

``````
``````

In [57]:

# Using just one list
d = {a:a**2 for a in range(0,3)}
print(d)

``````
``````

{0: 0, 1: 1, 2: 4}

``````
``````

In [58]:

# Nested comprehensions
# Transform a nested dictionary into a different nested dictionary.

nested_dict = {'something':{'a':1}, 'something_else':{'b':2}}
squared = {k: {k2 + " " + str(v2**2)
for (k2, v2)
in v.items()}
for (k, v)
in nested_dict.items()}
print(squared)

``````
``````

{'something': {'a 1'}, 'something_else': {'b 4'}}

``````

## Set comprehensions

These patterns create or transform other collections into sets. A set is an unordered collection, without duplicates.

Let's say we need to create a set from a list of numbers:

``````

In [59]:

s = [1,1,1,2,2,3,3,3,3,3,4,4,5]

normal_set = set(s)
print(normal_set)

``````
``````

{1, 2, 3, 4, 5}

``````
``````

In [60]:

# Using comprehension.

set_comprehension = {x for x in s}
print(set_comprehension)

``````
``````

{1, 2, 3, 4, 5}

``````
``````

In [61]:

# With transformation
set_comprehension = {x*2 + 1 for x in s}
print(set_comprehension)

``````
``````

{3, 5, 7, 9, 11}

``````
``````

In [62]:

# With conditions
set_comprehension = {x*2 + 1 for x in s if x>3}
print(set_comprehension)

``````
``````

{9, 11}

``````
``````

In [63]:

# With complex conditions
set_comprehension = {
(x**3 if x < 4
else x**2 )
for x in s}
print(set_comprehension)

``````
``````

{1, 8, 16, 25, 27}

``````

## Examples from real life

``````

In [64]:

# Flatten a matrix

matrix = [range(0,5), range(5,10), range(10,15)]

flatten = [column for row in matrix for column in row]
print(flatten)

``````
``````

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

``````
``````

In [68]:

# Removing a set of characters from a string

forbidden_chars = ["x", "z", "u"]
some_string = "Mr Garlax Underwood was a good man, but underpaid"
removed_list = [char for char in some_string if char.lower() not in forbidden_chars]
removed_as_string = "".join(removed_list)
print(removed_as_string)

``````
``````

Mr Garla nderwood was a good man, bt nderpaid

``````