Example solutions for script 08_functions

Exercise 3.2

The names of the arguments used in a functions declaration are arbitrary, you only must use them appropriately in the body of the function.

But try to find good names.

For example: Can you say if the following function is correct ?

def compute(a, b):
    return a + b

Now rename the name and the arguments and the programming mistake pops out:

def area_rectangle(width, height):
    return widht + height

Exercise 3.3

def average(a, b, c):
    return (a + b + c) / 3

print(average(1, 2, 6))
3.0

Exercise 4.1

def collatz(n):
    count = 0
    
    while n != 1:
        if n % 2 == 0:
            n = n // 2
        else:
            n = 3 * n + 1
       
        count += 1
    return count

iterations = collatz(42)
print("needed", iterations, "iterations")
needed 8 iterations

Exercise 4.2

import matplotlib.pyplot as plt
%matplotlib inline
x_values = []
y_values = []
for i in range(1, 10000):
    x_values.append(i)
    y_values.append(collatz(i))

plt.figure(figsize=(13,7))
plt.plot(x_values, y_values, "b.", markersize=.5)
plt.show()

Exercise 5.2 + 5.3

def maximum(li):
    if li == []:
        return None
    max_so_far = li[0]
    for i in range(1, len(li)):
        value = li[i]
        if value > max_so_far:
            max_so_far = value
    return max_so_far

print(maximum([]))
print(maximum([1]))
print(maximum([1, 2, 3]))
print(maximum([3, 2, 1]))
None
1
3
3

Alternative solution using list slicing + direct iteration over the list:

def maximum(li):
    if li == []:
        return None
    max_so_far = li[0]
    for value in li[1:]:
        if value > max_so_far:
            max_so_far = value
    return max_so_far

print(maximum([]))
print(maximum([1]))
print(maximum([1, 2, 3]))
print(maximum([3, 2, 1]))
None
1
3
3

We can use slicing of lists for making the code shorter, but also make it more expressive:

def maximum(li):
    if li == []:
        return None
    max_so_far = li[0]
    for value in li[1:]:
        if value > max_so_far:
            max_so_far = value
    return max_so_far

print(maximum([]))
print(maximum([1]))
print(maximum([1, 2, 3]))
print(maximum([3, 2, 1]))
None
1
3
3

Exercise 5.3

import math

def std_dev(li):
    n = len(li)
    if n == 0:
        return None
    elif n == 1:
        return 0.0
    avg = sum(li) / n
    deviations = 0.0
    for number in li:
        deviations += (number - avg) ** 2
    std_dev = math.sqrt(deviations / (n - 1))
    return std_dev

print(std_dev([]))
print(std_dev([1]))
print(std_dev([1,1,1]))
print(std_dev([1,2,3]))
None
0.0
0.0
1.0

Exercises 7.1 - 7.3

def min2(a, b):
    if a < b:
        return a
    else:
        return b
    
def min3(a, b, c):
    return min2(min2(a, b), c)

def min4(a, b, c, d):
    return min2(min2(a, b), min2(c, d))
 
print(min3(1, 2, 3))
print(min3(3, 2, 1))
print(min4(0, 1, 2, 3))
print(min4(3, 2, 1, 0))
1
1
0
0

Exercise 7.4

def is_prime(n):
    for i in range(2, n):
        if n % i == 0:
            return False
    return True

def all_prime(li):
    for number in li:
        if not is_prime(number):
            return False
    return True

def any_prime(li):
    for number in li:
        if is_prime(number):
            return True
    return False

print(all_prime([2, 3, 5]))
print(all_prime([2, 3, 5, 6]))
print(any_prime([2, 3, 5, 6]))
print(any_prime([4, 8, 9]))
True
False
True
False

Exercise block 8

import random


def ask_user():
    while True:
        move = input("please enter S, R, P or X: ").strip().upper()
        if move in ["R", "S", "P", "X"]:
            return move
        print("invalid input, please try again !")

        
def compute_move():
    return "RSP"[random.randint(0, 2)]


def detect_winner(move_a, move_b):
    if move_a == move_b:
        return 0
    if move_a + move_b in ["RS", "SP", "PR"]:
        return -1
    return 1


def one_round():
    user_move = ask_user()
    if user_move == "X":
        print("game stopped")
        return None
    
    computer_move = compute_move()
    print("computer plays", computer_move)
    
    outcome = detect_winner(user_move, computer_move)
    
    if outcome == 0:
        print("this is a tie !")
    elif outcome == -1:
        print("you win !")
    else:
        print("ha, computers can be clever, I win !")
    
    return outcome
    
def full_game():
    total = 0
    while True:
        outcome = one_round()
        if outcome == None:
            if total < 0:
                print("overall you are the winner !")
            elif total == 0:
                print("overall its a tie.")
            else:
                print("overall I am the winner !")
            return
        total += outcome
    
full_game()
    
please enter S, R, P or X: R
computer plays R
this is a tie !
please enter S, R, P or X: R
computer plays R
this is a tie !
please enter S, R, P or X: R
computer plays P
ha, computers can be clever, I win !
please enter S, R, P or X: x
game stopped
overall I am the winner !

Exercise block 9

import csv


def read_data(path):
    aa_to_mass = {}
    with open(path, "r") as fh:
        reader = csv.reader(fh)
        next(reader)
        for row in reader:
            aa_to_mass[row[0]] = float(row[4])
            
    return aa_to_mass
        
    
def compute_mass(aa_sequence, aa_to_mass):
    mass = 0
    for symbol in aa_sequence:
        mass += aa_to_mass[symbol]
    
    return mass - (len(aa_sequence) - 1) * 18.01528


def is_valid(sequence, allowed):
    for symbol in sequence:
        if symbol not in allowed:
            return False
    return True

def ask_user_for_valid_sequence(allowed):
    while True:
        sequence = input("please enter an amino acid sequence: ").upper().strip()
        if is_valid(sequence, allowed):
            return sequence
        print("invalid input, try again !")
        

aa_to_mass = read_data("amino_acids.csv")
sequence = ask_user_for_valid_sequence(aa_to_mass.keys())
print(compute_mass(sequence, aa_to_mass))
please enter an amino acid sequence: AAx
invalid input, try again !
please enter an amino acid sequence: AAA
231.25168
def compute_masses(fasta_path, aa_to_mass):
    
    with open(fasta_path, "r") as fh:

        sequence = ""
        for line in fh:
            line = line.rstrip()
            if line.startswith(">"):
                status_line = line.lstrip(">")
            elif line == "":
                print(status_line)
                print(compute_mass(sequence, aa_to_mass))
                sequence = ""
            else:
                sequence += line
            
# downloaded from https://siscourses.ethz.ch/python_dbiol/aa_sequences.fasta:

compute_masses("aa_sequences.fasta", aa_to_mass)
seq0
15254.646780000008
seq1
12726.93228
seq2
15254.646780000008
seq3
19608.910880000003
seq4
15359.707080000004
seq5
29198.85217999998
seq6
15359.707079999996
seq7
7831.985180000001
seq8
8165.428280000002
seq9
14640.864279999996
seq10
7320.302280000001
import csv

def transform_fasta(fasta_in, fasta_out, aa_to_mass):
    
    with open(fasta_in, "r") as fh_in, open(fasta_out, "w") as fh_out:
        
        writer = csv.writer(fh_out)
        sequence = ""
        
        for line in fh_in:
            line = line.rstrip()
            
            if line.startswith(">"):
                status_line = line.lstrip(">")
            elif line == "":
                writer.writerow([status_line, compute_mass(sequence, aa_to_mass)])
                sequence = ""
            else:
                sequence += line

transform_fasta("aa_sequences.fasta", "masses.csv", aa_to_mass)

print(open("masses.csv").read())
seq0,15254.646780000008
seq1,12726.93228
seq2,15254.646780000008
seq3,19608.910880000003
seq4,15359.707080000004
seq5,29198.85217999998
seq6,15359.707079999996
seq7,7831.985180000001
seq8,8165.428280000002
seq9,14640.864279999996
seq10,7320.302280000001