print("Hello, World")

"""
Explanation: Introduction to python
This notebook will teach the basics of python syntax through examples and excersies. There exists many different python tutorials, a good collection is here: https://wiki.python.org/moin/BeginnersGuide/Programmers
We start by running a simple Hello, World! program. To execute a cell in a jupyter notebook, select it and press shift+enter
End of explanation
"""


5 + 3

9 + 16

"""
Explanation: Basic python syntax
We will start with a quick run trough of the basic syntax of the python programming language
In python the "#" symbol specifies what follows it as a comment. This will not be executed it is just there to annotate the code

Simple calculations
Variables
Conditionals
Lists
Loops
Dictionaries
Functions and modules

Simple calculations
In python we can simply perform standard arethmetic functions. In a jupyter notebook, the output of the final line of the cell will be returned as the output.
End of explanation
"""


400*321

"""
Explanation: Excercise:
calculate 400 * 321
End of explanation
"""


height = 1.8
weight = 78

(height+weight)*2

# This is a comment
# We can store the result of calculation in a new variable

bmi = weight / height ** 2
bmi

"""
Explanation: Variables
To move forward we can define variables by using the assignment operator "=". We can then use these variables to perform for example arithmetic
End of explanation
"""


string_variable = "test" # A string
int_variable = 4 # An intenger
float_variable = 3.14 # a floating point number
height = int_variable * 2 
age = 2
name = "Rakoto"
print(int_variable + 4) # As we want to print out multiple things from this cell we use the print() statement
print(string_variable + " again")
print ("the name is "+ name +"and age =" + str(age))

# We can use the type() function to determine the type of the variable

print(type(string_variable))
print(type(int_variable))
print(type(float_variable))

# Sometimes python can convert between types automatically as in the BMI example above
print(type(height))
print(type(weight))
print(type(bmi)) 

# Other times not

string_variable + int_variable # This line will give a python error



"""
Explanation: Variable types
In python there are multiple types of variables describing different types of data. Three of the basic types are:

string: Describes text data
int: Describes integer numbers
float: Describes floating point numbers

Python is a dynamically typed language. This means that we do not have to declear the type of the variable when we createit, butw e still need to be careful about for example combining different types of variables
End of explanation
"""


# If we wanted to create the string "test4" we need to explicitly convert the initeger to a string

print(string_variable + str(int_variable))

# We can also convert from string to integer or float

print(float("3.14")**2) 


"""
Explanation: When writing python code we very often will run into this error messages. The errors come in many different types and learning to understand these messages can help the development process significantly. Normally the description at the end can give a lot of information. Here we see that we can not add an interger with a string
End of explanation
"""


t = True # Boolean true
f = False # Boolean false
print(type(t))

print("Equality " ,"test" == "test") # Test for equality with ==
print("Not Equal " ,"test" != "test") # Test for not equal with !=

print("And ", t and f) # Boolean and

print("Or ", t or f) # Boolean or

# Some more examples

print("3 == 3 is", 3 == 3)
print('"3" = 3 is',"3" == 3) # This will be false as "3" is a string and 3 is an integer

print ("3 > 2 is", 3 > 2) # Larger than
print ("2 >= 2 is", 2 >= 2) # Larger than or equal
print("2 < 3 is",2 < 3) # Smaller than
print("3 <= 2 is",3 <= 2) # Smaller than or equal


"""
Explanation: Excersice:
Create variables for the two sides of a rectangle and calculate the area (area = side_1 x side_2) and store that in a third variable. Set side_1 to 5 and side_2 to 8.
Conditionals
To create branches in the execution of the program we use conditionals. 
We start by consider a fourth data type in python. The bool type. It can only be either True or False.
Logical comparrissons in python are as follows:
End of explanation
"""


name = "Rania"
if name == "Rania":
    print("Hi Rania")
else:
    print("Who are you?")

name = "John"
if name == "Rania":
    print("Hi Rania")
else:
    print("Who are you?")

"""
Explanation: If statements
In python we use the if-else statements to branch the execution of the program. The if-else statement looks like this: 
if expression:
    action_if_true
else:
    action_if_false

Note that in python we use indentation(4 spaces) instead of {} to denote what belongs to a block.
End of explanation
"""


name = "Gunnar"
if name == "Rania":
    print("Hi Rania")
elif name == "Gunnar":
    print("Hi Gunnar")
else:
    print("Who are you?")


"""
Explanation: If we need to check for multiple conditions we can use the if - elif- else consturction. 
if expression1:
    action_if_true1
elif expression2:
    action_if_true2
  .
  .
  .        
else:
    action_if_false

We can use as many elif statements as we need. This code first tests if expression1 is true. If so it perfroms action_if_true1 and then the whole block is finished. If expression1 is false, expression2 is tested. If expression2 is true we do action_if_true2 etc.
End of explanation
"""


l = [1, 5, 9] # Defining a list
print(l)
print(type(l))

"""
Explanation: Excercise
Write an if statements that prints out "Positive" if a number is larger than 0, prints out 0 if the number is 0 and "Negative" if he number is negative. 
Lists
To store multiple objects in a list we use the python type: list. A list is defined using square brakcekts []
End of explanation
"""


l = [1, 5, 9]
print("First element", l[0])
print("Second element", l[1])
print("Thrid element", l[2])

# If we try to access an element that does not exist we get an error

print(l[5])

# We can edit individual elements in the list by assigning to them

l2 = ["a", "b", "c"]
print(l2)
l2[1] = "d"
print(l2)

"""
Explanation: We can access the elements of a list using the following syntax:
l[0]

The number in the brackets refer to the position in the list, with 0 being the first item
End of explanation
"""


l = ["a", "b"]
print(l)
l.append("c") # add an element to the end of the list
print(l)
l.remove("b") # Removes the element "b" from the list
print(l)
print(len(l)) # len(l) gives the length of a list

"""
Explanation: Lists have various useful fuctions that can be used to manipulate them. To see all you can use the python documentation at https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types
End of explanation
"""


developers = ["Jonathan", "Jyri", "Mix", "Gunnar"]

for developer in developers:
    print(developer)

"""
Explanation: Loops
In python we have two types of loops a for loop and a while loop. 
For loop
The structure of a for loop is as follows: 
    for item in list:
        action
So a for loop is used to iterate over each item in a list( or other similar data type)
End of explanation
"""


print(list(range(10))) # We need the extra list command as range returns a generator
# range(a) returns all the integers starting at 0 and ending a a-1
# We can also use range(3,6) to return the integer 3,4,5

for i in range(3,10): 
    print(i)

"""
Explanation: Often we want to loop a certain number of times. Then pythons range function is very useful. This function returns a generetor (almost a list) of all the integers.
End of explanation
"""


i = 0
while i < 10:
    print(i)
    i = i + 1 # We can also write this as i += 1

while True:
    number = int(input("Input a number and I will double it, type 0 to quit "))
    # We add the int() function as input returns a string
    if number == 0:
        break # We can use break to break out of a loop
    print(number * 2)

"""
Explanation: Excercise
Write a cell that calculates the sum of all the numbers less than 100
While loop
A while loop is used to run a loop for as long as a condition is true. It has this structure:
while condition: 
    action

For example
End of explanation
"""


num = int(input("Type in a number "))

# Your code goes here: 

"""
Explanation: Excersice
Finish the code below to print out all the numbers from the number the user entered to 0
End of explanation
"""


dictionary = {"key1": 3, "key2": 5} # Defining a dictionary
print(dictionary)
print(type(dictionary))

# We can access items in the same was as for lists:

print(dictionary["key1"])

"""
Explanation: Dictionaries
Often we want have a data type were we can store key:value pairs. In python we can do this with a dictionary. This is useful and also a very effecient way of storing and retreiving data
End of explanation
"""


for d in dictionary: # Loops through the keys
    print(d)
    
for d in dictionary.values(): #Looping through the values
    print(d)

"""
Explanation: Note that a dictionary is an unordered data type. So we can not expect a particular order if we want to loop through the dictionary
End of explanation
"""


d = {"key1": "a"}

print("key1 in d", "key1" in d)
print("key2 in d", "key2" in d)

l = [1, 4]
print("4 in l", 4 in l)
print("2 in l", 2 in l)

"""
Explanation: For both dictionaries and list it is easy to test if an element exists by using the in operator
End of explanation
"""



l = [1,2,3,5,5,2,7,1,1,1]
d = {}

# Your code goes here


"""
Explanation: Excersice
Write a short program that takes the list l below and calculates a dictionary that counts the number of duplicates in l with the keys being the valus. I.e if l = [1, 1, 5] the dictionary should be {1: 2, 5: 1} as we had two ones and one five.
End of explanation
"""


def double(x):
    """ Doubles the input value"""
    return x * 2

print(double(4))
print(double(17))

def alternative_len(l):
    """Calculates the length of a list"""
    length = 0
    for _ in l:
        length += 1
    return length

l = list(range(20,400))

print("Normal len", len(l))
print("Alternative len", alternative_len(l))

"""
Explanation: Functions and modules
To write resulable code and to structure our programs we write code in functions. A function is defined as follows in python: 
def function_name(argument1, argument2, ...):
    """ Docstring"""
   actions
   return return_value

The function take arguments are return values ( We can have a function without arguments and that does not return anything)
The docstring is a string describing the function
To call the function we use the the following syntax
result = function_name(argument1, argument2, ...)

There have been numerous examples of functions in the code above. For exmaple the len() function took a list as an argument and returned the length.
End of explanation
"""


import math

print(math.pi)

"""
Explanation: Modules and packages
Python has an extensive number of libraries and packages that perform various actions. If they are installed they can be imported like this: 
import math # imports the math modules
from math import pi # imports pi from the math module
End of explanation
"""


double = [x * 2 for x in range(10)]
double

# or a list of sine values
from math import sin, pi

sin_values = [sin(pi * i / 4) for i in range(9)]
sin_values

"""
Explanation: Many very useful stanrd libraries can be found at : https://docs.python.org/3/library/
There is also a hugh set of available libraries at https://pypi.python.org/pypi. These libraries can be installed using pip (https://docs.python.org/3/installing/)
Excersice
Write a function that takes the height and weight as a an argument and returns "normal" if the bmi < 25, "overweight" if the 25 < bmi < 30 and "obese" if bmi > 30
Extra: List comprehension
One often wants to create a list by looping through some values and performing some action on them. This can be implified in python using the list comprehension syntax. So we can define a list like this:
End of explanation
"""


