<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 5. Getting stuff done with Python
In this unit, we are going to  learn a new data structure with richer features compared to lists. The problem with lists, while flexible enough to store different data types in one variable, is that it does not provide us a way to "label" that information with meta data. For example in a list ['Andy', 28, 980.15], we would like to be able to associate with the value Andy a label or key 'name' so that we don't have to keep on recalling that a staff's name is located in the first position of the list.  
Secondly, we will cover the for and if else construct. 
Technically speaking, armed with the basic tools that we have learnt from the previous unit, we could go about writing code and basic scripts. But with these keywords, what can achieved is rather limited. Worse, the process of writing code will be tedious and unenlightening. From a scientific and analytic point of view, writing code is not only an ends to obtaining the results we want, but a way for us to structure our thinking and come to an understanding of the problem. 
5.1 Learning objectives for this unit
To use the dict data structure and related methods. 
To apply boolen conditionals to control if, if else and if elif statements. 
To use the for loop to iterate through repetitive calculations. 
6. The dictionary
Lists - while easy to create- have the weakness that one cannot easily retrieve data that has been already stored in it. Since the primary means of retrieving information in a list is via indexing and slicing, you need to know the exact integer positions of each data stored in the list. This can (and will often) lead to human errors in programming. Furthermore, an integer based recall is unenlightening. Other people who reads your code will find it difficult to understand what is being written. 
To remedy this, Python has built into its base package a data structure called dictionaries. A dictionary is simply a key-value pairing like so $$(key_1, value_1), (key_2, value_2)\ldots, (key_n, value_n)$$ where $key_i$ are usually (but not always) strings and $value_i$ any Python object (int, str, list and even other dict!) 
If my_dictionary is a dictionary. Then calling my_dictionary[key_1] will return you the value associated with key_1 in my_dictionary, say value_1. 
6.1 Creating dictionaries
Dictionaries are created using curly braces { }. Inside the curly braces, we simply list down all the key-value pairs with a colon 
Step1:  6.2 Updating dictionaries
Very often, we need to change dictionary values and/or add more entries to our dictionary.
Step2:  An implication of this is that we can start with an empty dictionary and add keys as we go along. 
And empty dictionary is created by assigning a variable to an instance of class dict by calling dict().
Step3:  6.2.1 Dictionary exercise
Here's what I want you to do. Go around the room and find out the favourite food of three colleagues here. Then update this empty dictionary with 3 key-value pairings where keys are your colleague's name and value his/her favourite food. Have fun!
Step4:  6.2.2 Using the .update method
To combine two dictionaries, we use the .update method.
Step5:  6.2.3 Creating dictionaries using kwargs
Dictionaries can also be created by calling dict() with keyword arguments (or kwargs). When we create dictionaries like this, the key value pairs are written as 
$$ key_1 = value_1, key_2 = value_2, \ldots $$ again each seperated by a comma.
Step6:  Note from the example above that when creating dictionaries, DO NOT enclose the keys within quotation marks. However, when accessing the value of a dictionary by its key, you MUST use quotation marks.
Step7:  7. If and boolen conditionals
Any algorithm worth its salt will have conditionals in it. Very rarely does an algorithm just proceed in a linear fashion, one step following another step. More often than not, one step will follow from another if some condition is satisfied. 
This situation can be programmed in Python by using the if keyword. The general construct of an if statement looks like this
Step8:  Here is our first example using the if keyword.
Step9:  The variable x has been assigned the value 300. When Python sees the statement if x == 300
Step10:  The conditional checks and see whether the remainder of 13 when divided by 2 is 0. (Recall that's what % does.) Since 13 returns 1 remainder when divided by 2, the condition is false. Hence the string 'This is an even number' is not printed. 
7.2 if else statements
If you look at the previous example,  one can see an obvious problem with this block of code. What if y=14? Then the output would consist of two print statements 'This is an even number' and followed by "I guess it's odd then". This is not desireable. In fact we want to print 'This is an even number' only when y is even and "I guess it's odd then" only when y is odd. To code this into Python, we use the else keyword. 
Code blocks under the else keyword are executed when the conditionals evaluate to False. 
The format of of if else statements are as below
Step11:  Try re-executing the cell above with various values of y and see the effect on the output. 
Nested if else statements make for horrible coding. It makes code hard to read and understand. Surely there must be a better way! 
7.3 elif to rescue
We use elif when we need to test conditionals in a sequential manner. A sequence of conditionals is tested, one after another until the first True condition is encountered. Then, the code block corresponding to that conditional is executed and program continues on without checking the other conditionals. 
The format of elif statements looks like this
Step12:  See how much more elegant this is instead of nested if else statements. 
Now let's try another example. This time we use elif to program Python to assign letter grades to student marks on an an exam. 
Here are the letter grade and their assigned intervals. 
| Grades | Interval       |
|
Step13:  As before, play around with the various values of marks to make sure that elif structure is working as intended. Notice that I phrased the conditional only to check agains a lower bound. This is because Python will only execute the code block corresponding to first True conditional in the elif sequence. Even if subsequent conditionals evaluate to true, their code is not run. 
8. Performing repetitive tasks. Using the for loop
Most algorithms consist of repeating a certain calculations or computer tasks in an almost similiar manner. To give a scenario, I could instruct Python to print the names of three staff members to the output. I could go about fulfilling this task by writing the following code 
print("Staff member Lisa")
print("Staff member Mark")
print("Staff member Andy")
Clearly this is repetitive and tedious. The for keyword allows us to simplify code by writing a single intruction - here print and looping this over a list consisting of staff names [Lisa, Mark, Andy]. 
The general format of a for loop is given by the following
Step14:  But Python allows us to write a more readable form of the for loop. So the following is equivalent to the above and is preferred.
Step15:  Note that the "counter variable" staff_name is actually a variable containing the current item in the list as the loop progresses. I could have used any name I wanted for the variable - I could use i to represent the staff's name. But I chose staff_name for readability purposes. As the variable staff_name runs through each item of staff, the code block print is executed with the current value of staff_name. Once that is done, the variable is updated with the next item in the list and the block is executed once more. This proceeds until the end of the list is reached and the for loop terminates. 
8.2 Combining for and if statements
To further control what each iteration of the for loop does, we can combine if statements within for statements to trigger certain instructions when   a particular iteration fulfils certain conditions. 
If we need to exit a for loop prematurely, we can use the break keyword. This is usually used in conjuction with if. When conditions for break is fulfilled, the for loop terminates immediately. Python will not evaluate for statements for remaining items in the iterating list.
Step16:  Here's a more mathematical usage of the for statement. Suppose we want to compute the decimal expansion of $\sqrt{2}$ accurate to 3 decimal places.After searching Wikipedia, I came up with this recursive formula $$\begin{align}a_0 &=1 \ a_{n+1} &= \frac{a_n}{2}+\frac{1}{a_n}\end{align}$$  Here's how we could implement this.
Step17:  8.2.1 Your mission, should you choose to accept it
...is to list down all prime numbers less than 100. 
A prime number $p$ is a number which is divisible only by 1 and itself.
<ASSISTANT_TASK:>
Python Code:
# creating a dictionary and assigning it to a variable 
staff = {'name': 'Andy', 'age': 28, 'email': 'andy@company.com' }
staff['name']
staff['age']
print(staff['email'])
# A dictionary is of class dict 
print(type(staff))
# list of all keys, note the brackets at the end. 
# .keys is a method associated to dictionaries
staff.keys()
# list of all values, in no particular order
staff.values()
# list all key-value pairings using .items
staff.items()
Explanation: 5. Getting stuff done with Python
In this unit, we are going to  learn a new data structure with richer features compared to lists. The problem with lists, while flexible enough to store different data types in one variable, is that it does not provide us a way to "label" that information with meta data. For example in a list ['Andy', 28, 980.15], we would like to be able to associate with the value Andy a label or key 'name' so that we don't have to keep on recalling that a staff's name is located in the first position of the list.  
Secondly, we will cover the for and if else construct. 
Technically speaking, armed with the basic tools that we have learnt from the previous unit, we could go about writing code and basic scripts. But with these keywords, what can achieved is rather limited. Worse, the process of writing code will be tedious and unenlightening. From a scientific and analytic point of view, writing code is not only an ends to obtaining the results we want, but a way for us to structure our thinking and come to an understanding of the problem. 
5.1 Learning objectives for this unit
To use the dict data structure and related methods. 
To apply boolen conditionals to control if, if else and if elif statements. 
To use the for loop to iterate through repetitive calculations. 
6. The dictionary
Lists - while easy to create- have the weakness that one cannot easily retrieve data that has been already stored in it. Since the primary means of retrieving information in a list is via indexing and slicing, you need to know the exact integer positions of each data stored in the list. This can (and will often) lead to human errors in programming. Furthermore, an integer based recall is unenlightening. Other people who reads your code will find it difficult to understand what is being written. 
To remedy this, Python has built into its base package a data structure called dictionaries. A dictionary is simply a key-value pairing like so $$(key_1, value_1), (key_2, value_2)\ldots, (key_n, value_n)$$ where $key_i$ are usually (but not always) strings and $value_i$ any Python object (int, str, list and even other dict!) 
If my_dictionary is a dictionary. Then calling my_dictionary[key_1] will return you the value associated with key_1 in my_dictionary, say value_1. 
6.1 Creating dictionaries
Dictionaries are created using curly braces { }. Inside the curly braces, we simply list down all the key-value pairs with a colon :. Different pairs are seperated by a ,.
End of explanation
# Hey, Andy mistakenly keyed in his age. He is actually 29 years old! 
staff['age'] = 29
print(staff)
# HR wants us to record down his staff ID. 
staff['id'] = 12345 
print(staff)
# Let's check the list of keys
staff.keys()
Explanation: 6.2 Updating dictionaries
Very often, we need to change dictionary values and/or add more entries to our dictionary.
End of explanation
favourite_food = dict() # You could also type favourite_food = {}
print(favourite_food)
Explanation: An implication of this is that we can start with an empty dictionary and add keys as we go along. 
And empty dictionary is created by assigning a variable to an instance of class dict by calling dict().
End of explanation
# update your dictionary here 
# and print the dictionary 
print(favourite_food)
Explanation: 6.2.1 Dictionary exercise
Here's what I want you to do. Go around the room and find out the favourite food of three colleagues here. Then update this empty dictionary with 3 key-value pairings where keys are your colleague's name and value his/her favourite food. Have fun!
End of explanation
staff.update({'salary': 980.15, 'department':'finance', 'colleagues': ['George', 'Liz']})
# Who are Andy's colleagues? Enter answer below 
# Which department does he work in? Enter answer below
Explanation: 6.2.2 Using the .update method
To combine two dictionaries, we use the .update method.
End of explanation
my_favourite_things = dict(food="Assam Laksa", music="classical", number = 2)
# my favourite number 
my_favourite_things['number']
Explanation: 6.2.3 Creating dictionaries using kwargs
Dictionaries can also be created by calling dict() with keyword arguments (or kwargs). When we create dictionaries like this, the key value pairs are written as 
$$ key_1 = value_1, key_2 = value_2, \ldots $$ again each seperated by a comma.
End of explanation
# An error
my_favourite_things[food]
# ...but this is correct 
food = 'food'
my_favourite_things[food]
Explanation: Note from the example above that when creating dictionaries, DO NOT enclose the keys within quotation marks. However, when accessing the value of a dictionary by its key, you MUST use quotation marks.
End of explanation
# examples of binary comparison 
1 < 2
# compound statements 
1 < 2 or 1 == 2
# using bitwise operators 
1<2 & 1==2
Explanation: 7. If and boolen conditionals
Any algorithm worth its salt will have conditionals in it. Very rarely does an algorithm just proceed in a linear fashion, one step following another step. More often than not, one step will follow from another if some condition is satisfied. 
This situation can be programmed in Python by using the if keyword. The general construct of an if statement looks like this: 
if condition :
do something
Python will only execute the code block do something only if condition evaluate to True. Otherwise it ignores it. Notice the lack of { } surrounding the code block to be executed. The Python interpreter relies on indentation and newline to "know" which code block is conditioned on. 
This enforces good coding style and makes it so nice to program with Python. No more worrying about unmatched braces! 
7.1 Conditionals
Since conditionals are logical statements, we need some binary comparison operators 
== logical equals to 
&gt; strictly greater than
&lt; strictly less than
!= logical not equals to 
We can create compound statements by using the keywords or and and. Their bitwise versions are | and &amp;.
End of explanation
x = 300
if x == 300:
    print('This is Sparta!')
Explanation: Here is our first example using the if keyword.
End of explanation
y = 13
print(y)
if y % 2 == 0:
    print('This is an even number')
print("I guess it's odd then")
Explanation: The variable x has been assigned the value 300. When Python sees the statement if x == 300: Python checks the conditional x==300 and evaluates it. Since x was assigned the value 300, the conditional is indeed True. When this happens, it executes the indented code block below the conditional, in this case print the string 'This is Sparta!'
End of explanation
y = 22 
if y%2 ==0:
    print("{} is an even number".format(y))
else:
    print("{} is an odd number".format(y))
y = 13 
if y%2 ==0:
    print("{} is an even number".format(y))
else:
    print("{} is an odd number".format(y))
# Nested if else statements
y = 25 
remainder = y%3
if remainder == 0:
    print("{} is divisible by 3".format(y))
else:
    print("{} is not divisible by 3".format(y))
    if remainder ==1:
        print("But has remainder {}".format(remainder))
    else:
        print("But has remainder {}".format(remainder))
Explanation: The conditional checks and see whether the remainder of 13 when divided by 2 is 0. (Recall that's what % does.) Since 13 returns 1 remainder when divided by 2, the condition is false. Hence the string 'This is an even number' is not printed. 
7.2 if else statements
If you look at the previous example,  one can see an obvious problem with this block of code. What if y=14? Then the output would consist of two print statements 'This is an even number' and followed by "I guess it's odd then". This is not desireable. In fact we want to print 'This is an even number' only when y is even and "I guess it's odd then" only when y is odd. To code this into Python, we use the else keyword. 
Code blocks under the else keyword are executed when the conditionals evaluate to False. 
The format of of if else statements are as below: 
if condition: 
do something
else:
do something else
End of explanation
y=25
remainder = y%3
if remainder == 0:
    div = 'is'
    s = 'Hence'
elif remainder == 1:
    div = 'is not'
    s = 'But'
elif remainder == 2:
    div = 'is not'
    s = 'But'
    
print('{} {} divisible by 3\n{} has remainder {}'.format(y, div, s, remainder)) 
Explanation: Try re-executing the cell above with various values of y and see the effect on the output. 
Nested if else statements make for horrible coding. It makes code hard to read and understand. Surely there must be a better way! 
7.3 elif to rescue
We use elif when we need to test conditionals in a sequential manner. A sequence of conditionals is tested, one after another until the first True condition is encountered. Then, the code block corresponding to that conditional is executed and program continues on without checking the other conditionals. 
The format of elif statements looks like this: 
if $condition_1$:
do code 1
elif $condition_2$:
do code 2
$\vdots$
elif $condition_n$:
do code n
elif chains can be "terminated" either by an elif statement itself or by an else if there is no final conditional to be evaluated. 
Let's try to refactor (recode) the nested if else statements above using the elif keyword.
End of explanation
marks = 78.35
if marks >= 80:
    grade = 'A'
elif marks >= 70:
    grade = 'B'
elif marks >= 60:
    grade = 'C'
elif marks >= 50:
    grade = 'D'
elif marks >= 45:
    grade = 'E'
else:
    grade = 'F'
print('Student obtained %.1f marks in the test and hence is awarded %s for this module' % (marks, grade))
Explanation: See how much more elegant this is instead of nested if else statements. 
Now let's try another example. This time we use elif to program Python to assign letter grades to student marks on an an exam. 
Here are the letter grade and their assigned intervals. 
| Grades | Interval       |
|:--------:|:----------:|
|A |[80, 100] |
|B |[70, 80) |
|C |[60, 70) |
|D | [50, 60) | 
|E | [45, 50) |
|F | [0, 45)|
End of explanation
staff = ['Lisa', 'Mark', 'Andy']
for i in range(0,3): # range(0,3) is a function that produces a sequence of numbers in the form of a list: [0,1,2]
    print("Staff member "+staff[i])
Explanation: As before, play around with the various values of marks to make sure that elif structure is working as intended. Notice that I phrased the conditional only to check agains a lower bound. This is because Python will only execute the code block corresponding to first True conditional in the elif sequence. Even if subsequent conditionals evaluate to true, their code is not run. 
8. Performing repetitive tasks. Using the for loop
Most algorithms consist of repeating a certain calculations or computer tasks in an almost similiar manner. To give a scenario, I could instruct Python to print the names of three staff members to the output. I could go about fulfilling this task by writing the following code 
print("Staff member Lisa")
print("Staff member Mark")
print("Staff member Andy")
Clearly this is repetitive and tedious. The for keyword allows us to simplify code by writing a single intruction - here print and looping this over a list consisting of staff names [Lisa, Mark, Andy]. 
The general format of a for loop is given by the following: 
for item_n in list:
    do code substituted with item_n
8.1 How a for loop works
Let's start by doing the above by looping over the index of the list. The way it is usually done in Javascript or C is to  declare a "counter variable" i and increment it by one to perform the next loop of the algorithm. We could do something like this in Python.
End of explanation
for staff_name in staff:
    print("Staff member "+ staff_name)
Explanation: But Python allows us to write a more readable form of the for loop. So the following is equivalent to the above and is preferred.
End of explanation
# A common programming interview task. Print 'foo' if x is divisible by 3 and 'bar' if it is divisible by 5 and 'baz' 
# if x is divisible by both 3 and 5. Do this for numbers 1 to 15. 
for num in range(1,16): # range(1,16) produces a list of numbers started from 1 and ending at 15. 
    if num % 3 == 0 and num % 5 !=0:
        print('%d foo' % (num))
    elif num % 5 == 0 and num % 3 != 0:
        print('%d bar' % (num))
    elif num % 5 == 0 and num % 3 == 0:
        print('%d baz' % (num))
    else:
        print('%d' % (num))
Explanation: Note that the "counter variable" staff_name is actually a variable containing the current item in the list as the loop progresses. I could have used any name I wanted for the variable - I could use i to represent the staff's name. But I chose staff_name for readability purposes. As the variable staff_name runs through each item of staff, the code block print is executed with the current value of staff_name. Once that is done, the variable is updated with the next item in the list and the block is executed once more. This proceeds until the end of the list is reached and the for loop terminates. 
8.2 Combining for and if statements
To further control what each iteration of the for loop does, we can combine if statements within for statements to trigger certain instructions when   a particular iteration fulfils certain conditions. 
If we need to exit a for loop prematurely, we can use the break keyword. This is usually used in conjuction with if. When conditions for break is fulfilled, the for loop terminates immediately. Python will not evaluate for statements for remaining items in the iterating list.
End of explanation
max_iter = 10
a = 1
# Since _ is considered a valid variable name, we can use this to
# "suppress" counting indices. 
for _ in range(0, max_iter): 
    a_next = a/2.0 + 1/a
    if abs(a_next-a) < 1e-4: # You can use engineering format numbers in Python
        print("Required accuracy found! Breaking out of the loop.")
        break  
    
    a = a_next
    
print("Approximation of sqrt(2) is: %.3f" % (a))        
Explanation: Here's a more mathematical usage of the for statement. Suppose we want to compute the decimal expansion of $\sqrt{2}$ accurate to 3 decimal places.After searching Wikipedia, I came up with this recursive formula $$\begin{align}a_0 &=1 \ a_{n+1} &= \frac{a_n}{2}+\frac{1}{a_n}\end{align}$$  Here's how we could implement this.
End of explanation
# Answer
Explanation: 8.2.1 Your mission, should you choose to accept it
...is to list down all prime numbers less than 100. 
A prime number $p$ is a number which is divisible only by 1 and itself.
End of explanation
<END_TASK>