List Comprehensions and Generators

Python comes with more than just a programming language, it also includes a way to write elegant code. Pythonic code is syntax that wishes to emulate natural constructs of programming.

Let's look at the basic syntax for a list comprehension:

some_list = [item for item in domain if .... ]

We store the item that exists in the domain into the list, as long as it passes any conditions in the if statement.

Example 1 Extract the even numbers from a given range.


In [4]:
# Store even numbers from 0 to 20
even_lst = [num for num in range(21) if num % 2 == 0]
print(even_lst)


[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

Example 2 Convert the reserved stock units (RSUs) an employee has in a company to the current cash value.


In [6]:
cash_value = 20
rsu_dict = {"Max":20, "Willie":13, "Joanna":14}

lst = [rsu_dict[name]*cash_value for name in rsu_dict]
print(lst)


[400, 280, 260]

In [9]:
my_dict = {"Ross":19, "Bernie":13, "Micah":15}
cash_value = 20

# [19*20, 13*20, 15*20]

cash_lst = [my_dict[key]*20 for key in my_dict]
print(cash_lst)


[260, 300, 380]

Let's take a look at some values and see how we can produce certain outputs.


In [10]:
rows = 'ABC'
cols = '123'
vowels = ('a', 'e', 'i', 'o', 'u')
sentence = 'cogito ergo sum'
words = sentence.split()

In [15]:
# Produce [A3, B2, C1]
number_letter_lst = [rows[element]+cols[2-element] for element in range(3)]
print(number_letter_lst)


['A3', 'B2', 'C1']

In [47]:
# Produce [A1, B1, C1, A2, B2, C2, A3, B3, C3]
letter_number_lst = [r+c for c in cols for r in rows]
print(letter_number_lst)


['A1', 'B1', 'C1', 'A2', 'B2', 'C2', 'A3', 'B3', 'C3']

In [52]:
x = [s1 + ' x ' + s2
            for s1 in (rows[i]+cols[i] for i in range(3))
            for s2 in (rows[2-j]+cols[j] for j in range(3))]
print(x)


['A1 x C1', 'A1 x B2', 'A1 x A3', 'B2 x C1', 'B2 x B2', 'B2 x A3', 'C3 x C1', 'C3 x B2', 'C3 x A3']

Generators

We can do more complex things than just the basic list comprehensions. We can create more complex, succint comprehensions by introducing generators in our very statements. We haev the following data to work with:

rows = 'ABC
cols = '123'

In general, we want to access both the rows in cols at the same time.... How did we do that?


In [57]:
# Simply accessing rows and cols in a comprehensions [A1, A2, A3, B1, B2, B3, C1, C2, C3]

# Non-Pythonic
lst = []
for r in rows:
    for c in cols:
        lst.append(r+c)
        
# Pythonic
lst = [r+c for r in rows for c in cols]
print(lst)


['A1', 'A2', 'A3', 'B1', 'B2', 'B3', 'C1', 'C2', 'C3']

Let's try Creating:

['A1 x C1', 'A1 x B2', 'A1 x A3', 'B2 x C1', 'B2 x B2', 'B2 x A3', 'C3 x C1', 'C3 x B2', 'C3 x A3']

Thought process, we know that rows will change every other 3, meaning we keep it constant...


In [72]:
# let's figure this list out with normal syntax
lst = []
for r in (rows[i]+cols[i] for i in range(3)):
    for c in (rows[2-i]+cols[i] for i in range(3)):
        lst.append(r + 'x' + c)
        
print(lst)


['A1xC1', 'A1xB2', 'A1xA3', 'B2xC1', 'B2xB2', 'B2xA3', 'C3xC1', 'C3xB2', 'C3xA3']

In [73]:
# shortened
crossed_list = [x + " x " + y for x in (rows[i]+cols[i] for i in range(3)) for y in (rows[2-i]+cols[i] for i in range(3))]

In [69]:
print(crossed_list)


['A1 x C1', 'A1 x B2', 'A1 x A3', 'B2 x C1', 'B2 x B2', 'B2 x A3', 'C3 x C1', 'C3 x B2', 'C3 x A3']

In [74]:
x = sorted(words, key=lambda x: len(x))

In [75]:
print(x)


['sum', 'ergo', 'cogito']

In [ ]: