# Comprehensions¶

Sometimes, it is useful to make some operations on Data Structures and return the same Data Structure. Examples may include squaring every element of a collection, constructing a lookup table and so on. Python provides an easier syntax for doing these tasks. Let’s understand comprehension techiniques by solving some problems

## Problem 1¶

**Given a list of integers, Create a new list containing their squares**

### Classic, `C`

like approach¶

```
In [3]:
```

```
num = [10,8,3,5,2,7,0,1,4,9,6]
num
```

```
Out[3]:
```

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

```
In [6]:
```

```
def square_classic_approach(x):
"""
Input: x - List of Integers
Return: A list containing squares of each element of list
"""
squared = [] # Empty list
for i in range(len(num)): # Equivalent to for(i=0;i<num;i++)
squared.append(num[i]**2) # Power operator
return squared
```

**Note**

Documentation of `Python`

code can be done using
docstringss like in
above code

```
In [7]:
```

```
square_classic_approach(num)
```

```
Out[7]:
```

```
[100, 64, 9, 25, 4, 49, 0, 1, 16, 81, 36]
```

### Comprehension Based Approach¶

```
In [13]:
```

```
def square_pythonic_approach(x): # Pythonic! :P
"""
Input: x - List of Integers
Return: A list containing squares of each element of list
"""
return [ num**2 for num in x ]
```

```
In [9]:
```

```
square_pythonic_approach(num)
```

```
Out[9]:
```

```
[100, 64, 9, 25, 4, 49, 0, 1, 16, 81, 36]
```

**Note**

Comprehension increases code readability. Comprehension can be applied to any collection.

## Problem 2¶

**Given a list of integers, square them if they are even number and
return a list**

### Classic, `C`

like approach¶

```
In [23]:
```

```
def square_if_even_classic_approach(x):
"""
Input: x - List of Integers
Return: A list containing squares of each element of list if element is even
"""
squared = [] # Empty list
for i in range(len(x)): # Equivalent to for(i=0;i<num;i++)
if x[i] % 2 == 0:
squared.append(x[i]**2) # Power operator
else:
squared.append(x[i])
return squared
```

```
In [24]:
```

```
square_if_even_classic_approach([10,9,2,4,5,67])
```

```
Out[24]:
```

```
[100, 9, 4, 16, 5, 67]
```

Observe how list is created and passed on the fly

## Comprehension based approach¶

```
In [16]:
```

```
def square_if_even_pythonic_approach(x): # Pythonic! :P
"""
Input: x - List of Integers
Return: A list containing squares of each element of list if element is even
"""
return [ num**2 if num % 2 == 0 else num for num in x ]
```

```
In [17]:
```

```
square_if_even_pythonic_approach(([10,9,2,4,5,67]))
```

```
Out[17]:
```

```
[100, 9, 4, 16, 5, 67]
```

## Problem 3¶

**Given a string, return the vowels occuring in it, ignoring the case**

```
In [31]:
```

```
def vowels_in(string):
"""
Input: string - a string
Return: List of vowels occuring in string
Example:
>>> vowels_in('Apple`)
['a','e']
"""
# We use a set because it stores unique elements
l_string = str.lower(string) # Converting to unique form
vowel_set = {c for c in l_string if c in 'aeiou'} # Note the imposal of condition
return sorted(list(vowel_set))
```

```
In [29]:
```

```
vowels_in('Apple')
```

```
Out[29]:
```

```
['a', 'e']
```

```
In [30]:
```

```
vowels_in('Karnataka')
```

```
Out[30]:
```

```
['a']
```

Above function can be written in more compact form

```
In [32]:
```

```
def vowels_in_compact(string):
"""
Input: string - a string
Return: List of vowels occuring in string
Example:
>>> vowels_in('Apple`)
['a','e']
"""
return sorted(list({c for c in str.lower(string) if c in 'aeiou'}))
```

```
In [33]:
```

```
vowels_in_compact('violin')
```

```
Out[33]:
```

```
['i', 'o']
```

## Problem 4¶

**Given a string, count the number of occurance of each character,
ignoring the case**

The nature of the problem makes us to use the dicionary data structure.

```
In [36]:
```

```
def alphabet_occurance_count(string):
"""
Input: a string
Output: the number of occurance od f each character in the string
"""
return {x:string.count(x) for x in string}
```

```
In [38]:
```

```
alphabet_occurance_count("Hello from Notebook")
```

```
Out[38]:
```

```
{' ': 2,
'H': 1,
'N': 1,
'b': 1,
'e': 2,
'f': 1,
'k': 1,
'l': 2,
'm': 1,
'o': 5,
'r': 1,
't': 1}
```

*Zen* revisited¶

In the beginning of this chapter, we looked at *Zen* of Python. Now we
inspect the things in **``this``** module **In the ``this`` module of
Python, ``this.s`` contains the encoded text, which has to be decoded
using ``this.d``. Decode it**

```
In [39]:
```

```
import this
```

```
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
```

Obviously, **this** is *Zen*

Now let’s have a look at other things in this module

```
In [40]:
```

```
this.c
```

```
Out[40]:
```

```
97
```

```
In [41]:
```

```
this.d
```

```
Out[41]:
```

```
{'A': 'N',
'B': 'O',
'C': 'P',
'D': 'Q',
'E': 'R',
'F': 'S',
'G': 'T',
'H': 'U',
'I': 'V',
'J': 'W',
'K': 'X',
'L': 'Y',
'M': 'Z',
'N': 'A',
'O': 'B',
'P': 'C',
'Q': 'D',
'R': 'E',
'S': 'F',
'T': 'G',
'U': 'H',
'V': 'I',
'W': 'J',
'X': 'K',
'Y': 'L',
'Z': 'M',
'a': 'n',
'b': 'o',
'c': 'p',
'd': 'q',
'e': 'r',
'f': 's',
'g': 't',
'h': 'u',
'i': 'v',
'j': 'w',
'k': 'x',
'l': 'y',
'm': 'z',
'n': 'a',
'o': 'b',
'p': 'c',
'q': 'd',
'r': 'e',
's': 'f',
't': 'g',
'u': 'h',
'v': 'i',
'w': 'j',
'x': 'k',
'y': 'l',
'z': 'm'}
```

It looks like a mapping from one character to another… Hmm… Interesting!

```
In [42]:
```

```
this.i
```

```
Out[42]:
```

```
25
```

```
In [43]:
```

```
this.s
```

```
Out[43]:
```

```
"Gur Mra bs Clguba, ol Gvz Crgref\n\nOrnhgvshy vf orggre guna htyl.\nRkcyvpvg vf orggre guna vzcyvpvg.\nFvzcyr vf orggre guna pbzcyrk.\nPbzcyrk vf orggre guna pbzcyvpngrq.\nSyng vf orggre guna arfgrq.\nFcnefr vf orggre guna qrafr.\nErnqnovyvgl pbhagf.\nFcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.\nNygubhtu cenpgvpnyvgl orngf chevgl.\nReebef fubhyq arire cnff fvyragyl.\nHayrff rkcyvpvgyl fvyraprq.\nVa gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.\nGurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.\nNygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.\nAbj vf orggre guna arire.\nNygubhtu arire vf bsgra orggre guna *evtug* abj.\nVs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.\nVs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.\nAnzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"
```

Wow!…Looks like encoded text.

We will decode it using `this.d`

mapping

```
In [47]:
```

```
decoded = ''.join([this.d[c] if str.isalnum(c) else c for c in this.s]) # join() joins the iterable with string
print(decoded)
```

```
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
```

This is again ***Zen of Python!***

In fact **``this``** module uses a function to build the *Translation
Table ``d``* in it’s `__init.py__`

to print the ***Zen***. The
encoding done here is `rot13`

encoding. We will look about modules in
upcoming chapters.

## Fibonacci Again¶

Now you have understood the lists and operations. Let’s look at a recursive Fibonacci Number Generator

```
In [53]:
```

```
def fibonacci_recursive(n,first=0,second=1):
return [] if n == 0 else [first] + fibonacci_recursive(n - 1, second, first + second)
```

```
In [54]:
```

```
fibonacci_recursive(5)
```

```
Out[54]:
```

```
[0, 1, 1, 2, 3]
```

# Filtering Lists - Need for `lambda`

s¶

In Python, functions are also objects. It means that you can pass them
to other function like a variable. This flexibility of functions allows
us to do many useful tasks. `filter`

ing a collection is one of them.

## Problem : Find even numbers in a given sequence¶

### Solution 1: Use List comprehension¶

```
In [55]:
```

```
x = [0,1,3,5,8,7,6]
```

```
In [57]:
```

```
evens = [i for i in x if i%2 == 0]
evens
```

```
Out[57]:
```

```
[0, 8, 6]
```

### Solution 2: Use `filter`

with functions¶

`filter`

function takes a list and a function returning bool as
argument and `filter`

’s the list, returns the iterator through
`filter`

ed list. One can use `list()`

to convert iterator to a
list

Usage

```
result = list(filter(condition,collection))
```

`condition`

is a boolean function that takes an element as input

```
In [58]:
```

```
def is_even(item):
return item % 2 == 0
```

```
In [61]:
```

```
list(filter(is_even,x))
```

```
Out[61]:
```

```
[0, 8, 6]
```

## Solution 3: Use s¶

In previous example, we passed a function object to `filter()`

. The
same case happens in many situations. In some cases function to be
passed might be too short like `is_even()`

. In this case `lambda`

s
can be used. `lambda`

s create function in place.

Usage:

```
function_name = lambda argument_list : executable_statements
```

This has the same effect as that of

```
def function_name(argument_list):
executable_statements
```

Now our `is_even`

function can be defined in terms of lambdas

```
is_even = lambda x : x % 2 == 0 # Note that return may be omitted
```

If multi-line statements are needed, Statements can be put inside
`()`

s or line can be extended with `\`

s

```
In [62]:
```

```
list(filter(lambda x: x % 2 == 0,x))
```

```
Out[62]:
```

```
[0, 8, 6]
```

Lambdas are a fundamental concept of *Functional Programming* where
every task is achieved via a function. They constitute the basis of a
branch of Mathematics and Computation Theory called **:math:`lambda`
calculus**.

As a final thought, we shall see Recursive Fibonacci Generator in terms
of `lambda`

s

```
In [5]:
```

```
fibonacci_lambda = \
lambda n,first=0,second=1 :\
[] if n == 0 \
else \
[first] + fibonacci_lambda(n - 1, second, first + second)
```

```
In [6]:
```

```
fibonacci_lambda(4)
```

```
Out[6]:
```

```
[0, 1, 1, 2]
```

Note that lines are broken with `\`