# 7   Control Flow Statements¶

## 7.1   Exercises¶

### 7.1.1   Exercise¶

The Fibonacci sequence are the numbers in the following integer sequence:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...

By definition, the first two numbers in the Fibonacci sequence are 0 and 1, and each subsequent number is the sum of the previous two. The Fibonacci suite can be defined as following:

F0 = 0, F1 = 1.

Fn = Fn-1 + Fn-2

Write a function which take an integer n as parameter and returns a list containing the n first number of the Fibonacci sequence.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42  def fibonacci(n): """ compute the suite of fibonacci for n element and return it for instance :: fibonacci(7) [0, 1, 1, 2, 3, 5, 8, 13, 21] :param int n: the nth elemnt of the fibonacci suite :return: the nfirst elt of the fibonacci suite :rtype: list of int """ fib_suite = [] i = 0 while i <= n: if i == 0: fib_suite.append(0) elif i == 1: fib_suite.append(1) else: res = fib_suite[-1] + fib_suite[-2] fib_suite.append(res) i += 1 return fib_suite print(', '.join([str(i) for i in fibonacci(10)])) def fibonacci_2(n): """ compute the fibonacci of the elt n :param int n: :return: the fibonacci of the elt n :rtype: int """ a = 0 b = 1 for i in range(n): a, b = b, a + b return b 

fibonacci_iteration.py . We will see another way more elegant to implement the Fibonacci suite in Advanced Programming Techniques section.

### 7.1.2   Exercise¶

Reimplement your own function max (my_max). This function will take a list or tuple of float or integer and returns the largest element?

Write the pseudocode before to propose an implementation.

#### 7.1.2.1   pseudocode¶

function my_max(l)
max <- first elt of l
for each elts of l
if elt is > max
max <- elt
return max

#### 7.1.2.2   implementation¶

def my_max(seq):
"""
return the maximum value in a sequence
work only with integer or float
"""
highest = seq[0]
for i in seq:
if i > highest:
highest = i
return highest

l = [1, 2, 3, 4, 58, 9]
print(my_max(l))
58


### 7.1.3   Exercise¶

We want to establish a restriction map of a sequence.
But we will do this step by step,
and reuse the enzymes used in previous chapter:
• Create a function that takes a sequence and an enzyme as parameters, and returns
the position of the first binding site. (Write the pseudocode.)

pseudocode

function one_enz_binding_site(dna, enzyme)
if enzyme binding site is substring of dna
return of first position of substring in dna

implementation

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from operator import itemgetter # we decide to implement enzyme as tuple with the following structure # (name, comment, sequence, cut, end) # 0 1 2 3 4 def one_enz_one_binding_site(dna, enzyme): """ :return: the first position of enzyme binding site in dna or None if there is not :rtype: int or None """ pos = dna.find(enzyme[2]) if pos != -1: return pos 
• Improve the previous function to return all positions of binding sites.

pseudocode of first algorithm

function one_enz_binding_sites(dna, enzyme)
positions <- empty
if enzyme binding site is substring of dna
add the position of the first substring in dna in positions
positions <- find binding_sites in rest of dna sequence
return positions

implementation

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  def one_enz_all_binding_sites(dna, enzyme): """ :param dna: the dna sequence to search enzyme binding sites :type dna: str :param enzyme: the enzyme to looking for :type enzyme: a tuple (str name, str comment, str sequence, int cut, str end) :return: all positions of enzyme binding sites in dna :rtype: list of int """ positions = [] pos = dna.find(enzyme[2]) while pos != -1: positions.append(pos) pos = dna.find(enzyme[2], pos + 1) return positions 

pseudocode of second algorithm

function one_enz_all_binding_sites_2(dna, enzyme)
positions <- empty
find first position of binding site in dna
while we find binding site in dna
add position of binding site to positions
find first position of binding site in dna in rest of dna
return positions

implementation

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23  def one_enz_all_binding_sites2(dna, enzyme): """ :param dna: the dna sequence to search enzyme binding sites :type dna: str :param enzyme: the enzyme to looking for :type enzyme: a tuple (str name, str comment, str sequence, int cut, str end) :return: all positions of enzyme binding sites in dna :rtype: list of int """ positions = [] pos = dna.find(enzyme[2]) while pos != -1: if positions: positions.append(pos) else: positions = pos + positions[-1] new_seq = dna[pos + 1:] pos = new_seq.find(enzyme[2]) pos = pos return positions 
• Search all positions of Ecor1 binding sites in dna_1.
ecor1 = ("EcoRI", "Ecoli restriction enzime I", "gaattc", 1, "sticky")

dna_1 = """tcgcgcaacgtcgcctacatctcaagattcagcgccgagatccccgggggttgagcgatccccgtcagttggcgtgaattcag
cagcagcgcaccccgggcgtagaattccagttgcagataatagctgatttagttaacttggatcacagaagcttccaga
ccaccgtatggatcccaacgcactgttacggatccaattcgtacgtttggggtgatttgattcccgctgcctgccagg"""

• Generalize the binding sites function to take a list of enzymes and return a list of tuples (enzyme name, position).

pseudocode

function binding_sites(dna, set of enzymes)
positions <- empty
for each enzyme in enzymes
pos <- one_enz_binding_sites(dna, enzyme)
pos <- for each position create a tuple enzyme name, position
positions <- pos
return positions

implementation

In bonus, we can try to sort the list in the order of the position of the binding sites like this:

[('Sau3aI', 38), ('SmaI', 42), ('Sau3aI', 56), ('EcoRI', 75), ...

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21  def binding_sites(dna, enzymes): """ return all positions of all enzymes binding sites present in dna sort by the increasing position. :param dna: the dna sequence to search enzyme binding sites :type dna: str :param enzymes: the enzymes to looking for :type enzymes: a sequence of enzyme tuple :return: all positions of each enzyme binding sites in dna :rtype: list of int """ positions = [] for enzyme in enzymes: pos = one_enz_all_binding_sites(dna, enzyme) pos = [(enzyme[0], pos) for pos in pos] positions.extend(pos) positions.sort(key=itemgetter(1)) return positions 
ecor1 = ("EcoRI", "Ecoli restriction enzime I", "gaattc", 1, "sticky")
ecor5 = ("EcoRV", "Ecoli restriction enzime V", "gatatc", 3, "blunt")
bamh1 = ("BamHI", "type II restriction endonuclease from Bacillus amyloliquefaciens ", "ggatcc", 1, "sticky")
hind3 = ("HindIII", "type II site-specific nuclease from Haemophilus influenzae", "aagctt", 1 , "sticky")
taq1 = ("TaqI", "Thermus aquaticus", "tcga", 1 , "sticky")
not1 = ("NotI", "Nocardia otitidis", "gcggccgc", 2 , "sticky")
sau3a1 = ("Sau3aI", "Staphylococcus aureus", "gatc", 0 , "sticky")
hae3 = ("HaeIII", "Haemophilus aegyptius", "ggcc", 2 , "blunt")
sma1 = ("SmaI", "Serratia marcescens", "cccggg", 3 , "blunt")


and the two dna fragments:

dna_1 = """tcgcgcaacgtcgcctacatctcaagattcagcgccgagatccccgggggttgagcgatccccgtcagttggcgtgaattcag
cagcagcgcaccccgggcgtagaattccagttgcagataatagctgatttagttaacttggatcacagaagcttccaga
ccaccgtatggatcccaacgcactgttacggatccaattcgtacgtttggggtgatttgattcccgctgcctgccagg"""

dna_2 = """gagcatgagcggaattctgcatagcgcaagaatgcggccgcttagagcgatgctgccctaaactctatgcagcgggcgtgagg
attcagtggcttcagaattcctcccgggagaagctgaatagtgaaacgattgaggtgttgtggtgaaccgagtaag
agcagcttaaatcggagagaattccatttactggccagggtaagagttttggtaaatatatagtgatatctggcttg"""

enzymes= (ecor1, ecor5, bamh1, hind3, taq1, not1, sau3a1, hae3, sma1)
binding_sites(dna_1, enzymes)
[('Sau3aI', 38), ('SmaI', 42), ('Sau3aI', 56), ('EcoRI', 75), ('SmaI', 95), ('EcoRI', 105),
('Sau3aI', 144), ('HindIII', 152), ('BamHI', 173), ('Sau3aI', 174), ('BamHI', 193), ('Sau3aI', 194)]

binding_sites(dna_2, enzymes)
[('EcoRI', 11), ('NotI', 33), ('HaeIII', 35), ('EcoRI', 98), ('SmaI', 106),
('EcoRI', 179), ('HaeIII', 193), ('EcoRV', 225)]


#### 7.1.3.1   Bonus¶

If you prefer the enzyme implemented as namedtuple:

### 7.1.4   Exercise¶

Write a uniqify_with_order function that takes a list and returns a new list without any duplicate, but keeping the order of items. For instance:

>>> l = [5, 2, 3, 2, 2, 3, 5, 1]
>>> uniqify_with_order(l)
[5, 2, 3, 1]


Solution

>>> uniq = []
>>> for item in l:
>>>   if item not in uniq:
>>>      uniq.append(item)


Solution

>>> uniq_items = set()
>>> l_uniq = [x for x in l if x not in uniq_items and not uniq_items.add(x)]