#!/usr/bin/env python # coding: utf-8 # # Introduction to programming for Geoscientists through Python # ### [Gerard Gorman](http://www.imperial.ac.uk/people/g.gorman), [Nicolas Barral](http://www.imperial.ac.uk/people/n.barral) # # # Lecture 2: Conditional expressions, loops and lists # Learning objectives: # # * Know how to form a *condition* using a *boolean expression*. # * Be able to use a conditional expression in combination with a *while-loop* to perform repetitive tasks. # * Be able to store data elements within a Python *list*. # * Be able to use a *for-loop* to iterate, and perform some task, over a *list* of elements. # ## Boolean expressions # An expression with value *true* or *false* is called a boolean expression. Example expressions for what you would write mathematically as # $C=40$, $C\ne40$, $C\ge40$, $C\gt40$ and $C\lt40$ are: # # ```python # C == 40 # Note: the double == checks for equality! # C != 40 # This could also be written as 'not C == 4' # C >= 40 # C > 40 # C < 40 # ``` # We can test boolean expressions in a Python shell: # In[1]: C = 41 print("C != 40: ", C != 40) print("C < 40: ", C < 40) print("C == 41: ", C == 41) # Several conditions can be combined with the special 'and' and 'or' keywords into a single boolean expression: # # * Rule 1: (**C1** *and* **C2**) is *True* only if both **C1** and **C2** are *True* # * Rule 2: (**C1** *or* **C2**) is *True* if either **C1** or **C2** are *True* # # Examples: # In[2]: x=0; y=1.2 print (x >= 0 and y < 1) # ## Exercise 2.1: Values of boolean expressions # Add a comment to the code below to explain the outcome of each of the boolean expressions: # In[3]: C = 41 print("Case 1: ", C == 40) print("Case 2: ", C != 40 and C < 41) print("Case 3: ", C != 40 or C < 41) print("Case 4: ", not C == 40) print("Case 5: ", not C > 40) print("Case 6: ", C <= 41) print("Case 7: ", not False) print("Case 8: ", True and False) print("Case 9: ", False or True) print("Case 10: ", False or False or False) print("Case 11: ", True and True and False) print("Case 12: ", False == 0) print("Case 13: ", True == 0) print("Case 14: ", True == 1) # ## Loops # Suppose we want to make a table of Celsius and Fahrenheit degrees: # ``` # -20 -4.0 # -15 5.0 # -10 14.0 # -5 23.0 # 0 32.0 # 5 41.0 # 10 50.0 # 15 59.0 # 20 68.0 # 25 77.0 # 30 86.0 # 35 95.0 # 40 104.0 # ``` # How do we write a program that prints out such a table? #  # We know from the last lecture how to make one line in this table: # In[4]: C = -20 F = 9.0/5*C + 32 print(C, F) # We can just repeat these statements: # In[5]: C=-20; F=9.0/5*C+32; print(C,F) C=-15; F=9.0/5*C+32; print(C,F) C=-10; F=9.0/5*C+32; print(C,F) C=-5; F=9.0/5*C+32; print(C,F) C=0; F=9.0/5*C+32; print(C,F) C=5; F=9.0/5*C+32; print(C,F) C=10; F=9.0/5*C+32; print(C,F) C=15; F=9.0/5*C+32; print(C,F) C=20; F=9.0/5*C+32; print(C,F) C=25; F=9.0/5*C+32; print(C,F) C=30; F=9.0/5*C+32; print(C,F) C=35; F=9.0/5*C+32; print(C,F) C=40; F=9.0/5*C+32; print(C,F) # So we can see that works but its **very boring** to write and very easy to introduce a misprint. # # **You really should not be doing boring repetitive tasks like this.** Spend one time instead looking for a smarter solution. When programming becomes boring, there is usually a construct that automates the writing. Computers are very good at performing repetitive tasks. For this purpose we use **loops**. # ## The while loop (and the significance of indentation) # A while loop executes repeatedly a set of statements as long as a **boolean** (i.e. *True* / *False*) condition is *True* # # ``` # while condition: # # # ... # # ``` # Note that all statements to be executed within the loop must be indented by the same amount! The loop ends when an unindented statement is encountered. # # At this point it is worth noticing that **blank spaces may or may not be important** in Python programs. These statements are equivalent (blanks do not matter): # In[6]: v0=3 v0 = 3 v0= 3 # The computer does not care but this formatting style is # considered clearest for the human reader. v0 = 3 # Here is a while loop example where blank spaces really do matter: # In[7]: counter = 0 while counter <= 10: counter = counter + 1 print(counter) # Let's take a look at what happens when we forget to indent correctly: # In[8]: counter = 0 while counter <= 10: counter = counter + 1 print(counter) # Let's use the while loop to create the table above: # In[9]: C = -20 # Initialise C dC = 5 # Increment for C within the loop while C <= 40: # Loop heading with condition F = (9.0/5)*C + 32 # 1st statement inside loop print(C, F) # 2nd statement inside loop C = C + dC # Increment C for the next iteration of the loop. # ## Exercise 2.2: Make a Fahrenheit-Celsius conversion table # Write a program that prints out a table with Fahrenheit degrees 0, 10, 20, ..., 100 in the first column and the corresponding Celsius degrees in the second column. # # Hint: $C = \frac{5}{9}(F-32)$ # In[ ]: # ## Exercise 2.3: Write an approximate Fahrenheit-Celsius conversion table # Many people use an approximate formula for quickly converting Fahrenheit ($F$) to Celsius ($C$) degrees:

# $C \approx \hat{C} = \frac{F − 30}{2}$

# Modify the program from the previous exercise so that it prints three columns: $F$, $C$, and the approximate value $\hat{C}$. # In[ ]: # ## Lists # So far, one variable has referred to one number (or string). Sometimes however we naturally have a collection of numbers, say # degrees −20, −15, −10, −5, 0, ..., 40. One way to store these values in a computer program would be to have one variable per value, i.e. # In[10]: C1 = -20 C2 = -15 C3 = -10 # ... C13 = 40 # This is clearly a terrible solution, particularly if we have lots of values. A better way of doing this is to collect values together in a list: # In[11]: C = [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40] # Now there is just one variable, **C**, holding all the values. Elements in a list are accessed via an index. List indices are always numbered as 0, 1, 2, and so forth up to the number of elements minus one: # In[12]: mylist = [4, 6, -3.5] print(mylist[0]) print(mylist[1]) print(mylist[2]) print(len(mylist)) # length of list # Here are a few example of operations that you can perform on lists: # In[13]: C = [-10, -5, 0, 5, 10, 15, 20, 25, 30] C.append(35) # add new element 35 at the end print(C) # In[14]: C=C+[40,45] # And another list to the end of C print(C) # In[15]: C.insert(0, -15) # Insert -15 as index 0 print(C) # In[16]: del C[2] # delete 3rd element print(C) # In[17]: del C[2] # delete what is now 3rd element print(C) # In[18]: print(len(C)) # length of list # In[19]: print(C.index(10)) # Find the index of the list with the value 10 # In[20]: print(10 in C) # True only if the value 10 is stored in the list # In[21]: print(C[-1]) # The last value in the list. # In[22]: print(C[-2]) # The second last value in the list. # You can also extract sublists using ":" # In[23]: print(C[5:]) # From index 5 to the end of the list. # In[24]: print(C[5:7]) # From index 5 up to, but not including index 7. # In[25]: print(C[7:-1]) # From index 7 up to the second last element. # In[26]: print(C[:]) # [:] specifies the whole list. # You can also unpack the elements of a list into seperate variables: # In[27]: somelist = ['Curly', 'Larry', 'Moe'] stooge1, stooge2, stooge3 = somelist print(stooge3, stooge2, stooge1) # ## Exercise 2.4: Store odd numbers in a list # # Step 1: Write a program that generates all odd numbers from 1 to *n*. Set *n* in the beginning of the program and use a while loop to compute the numbers. (Make sure that if *n* is an even number, the largest generated odd number is *n*-1.). # # Step 2: Store the generated odd numbers in a list. Start with an empty list and use the same while loop where you generate each odd number, to append the new number to the list. # # Finally, print the list elements to the screen. # In[ ]: # ## For loops # We can visit each element in a list and process the element with some statements using a *for* loop, for example: # In[28]: degrees = [0, 10, 20, 40, 100] for C in degrees: print('list element:', C) print('The degrees list has', len(degrees), 'elements') # Notice again how the statements to be executed within the loop must be indented! Let's now revisit the conversion table example using the *for* loop: # In[29]: Cdegrees = [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40] for C in Cdegrees: F = (9.0/5)*C + 32 print(C, F) # We can easily beautify the table using the printf syntax that we encountered in the last lecture: # In[30]: for C in Cdegrees: F = (9.0/5)*C + 32 print('%5d %5.1f' % (C, F)) # It is also possible to rewrite the *for* loop as a *while* loop, i.e., # # ``` # for element in somelist: # # process element # ``` # can always be transformed to a *while* loop # ``` # index = 0 # while index < len(somelist): # element = somelist[index] # # process element # index += 1 # ``` # Taking the previous table example: # In[31]: Cdegrees = [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40] index = 0 while index < len(Cdegrees): C = Cdegrees[index] F = (9.0/5)*C + 32 print('%5d %5.1f' % (C, F)) index += 1 # Rather than just printing out the Fahrenheit values, let's also store these computed values in a list of their own: # In[32]: Cdegrees = [-20, -15, -10, -5, 0, 5, 10, 15, 20, 25, 30, 35, 40] Fdegrees = [] # start with empty list for C in Cdegrees: F = (9.0/5)*C + 32 Fdegrees.append(F) # add new element to Fdegrees print(Fdegrees) # In Python *for* loops usually loop over list values (elements), i.e., # # ``` # for element in somelist: # ...process variable element # ``` # However, we can also loop over list indices: # # ``` # for i in range(0, len(somelist), 1): # element = somelist[i] # ... process element or somelist[i] directly # ``` # The statement *range(start, stop, inc)* generates a list of integers *start*, *start+inc*, *start+2\*inc*, and so on up to, but not including, *stop*. We can also write *range(stop)* as an abbreviation for *range(0, stop, 1)*: # In[33]: print(range(3)) # same as range(0, 3, 1) # In[34]: print(range(2, 8, 3)) # ## List comprehensions # Consider this example where we compute two lists in a *for* loop: # In[35]: n = 16 Cdegrees = []; Fdegrees = [] # empty lists for i in range(n): Cdegrees.append(-5 + i*0.5) Fdegrees.append((9.0/5)*Cdegrees[i] + 32) print("Cdegrees = ", Cdegrees) print("Fdegrees = ", Fdegrees) # As constructing lists is a very common requirement, the above way of doing it can become very tedious to both write and read. Therefore, Python has a compact construct, called list comprehension for generating lists from a *for* loop: # In[36]: n = 16 Cdegrees = [-5 + i*0.5 for i in range(n)] Fdegrees = [(9.0/5)*C + 32 for C in Cdegrees] print("Cdegrees = ", Cdegrees) print("Fdegrees = ", Fdegrees) # The general form of a list comprehension is: # ``` # somelist = [expression for element in somelist] # ``` # ## Exercise 2.5: Repeat the previous exercise using: a for loop, list comprehension and the range function # In[37]: # Using for loop # In[38]: # Using list comprehension # In[39]: # Using the function range