5  Basic Programming Techniques

Chapter Learning Objectives
  • Branching
  • Looping

In this section we cover the main branching and looping methods in Python. We use loops if we have codes that needs to get repeated. We use branching if we want to evaluate alternative parts of our codes depending on a runtime condition.

5.1 Branching into Alternative Code Blocks

5.1.1 The if statement

The if command can be used to check whether a certain condition is true. If it is true, then we can assign a certain chain of commands (i.e., a block of code) for this eventuality. If, on the other hand, the condition in the if statement is wrong, we can branch off our program into another direction and assign different commands (i.e., an alternative code block). This allows us to branch our program into two (or more) separate possible directions. The if construct is illustrated in Figure 5.1.

Figure 5.1: If Branching Illustration

In Python it is very important to get the "indentation" right. So all the commands that we want to be executed after the if statement need to be "indented" by 4 spaces (just hit the tab-key on your keyboard once). Python does not use the curly brackets {} that R, Stata, Java, C or other programming languages use in their versions of the if-statements and for-loops.

Here is a simple example of an if statement that is used to branch the code into two alternate routes depending on the value stored in variable x. You can read the if statement below as "if the value of x is larger than one half, then do one thing. If it is not, then do the other thing."

x = 2
if (x > 0.5):
    print("Number x= {} is greater than 0.5".format(x))
else:
    print("Number x= {} is smaller than or equal to 0.5".format(x))
Number x= 2 is greater than 0.5
x <- 2

if (x > 0.5) {
  cat("Number x =", x, "is greater than 0.5\n")
} else {
  cat("Number x =", x, "is smaller than or equal to 0.5\n")
}
Number x = 2 is greater than 0.5

The operators that you can use in the if statements include the following:

Operator Description Example
== Equals x == y
!= Not equals x != y
> Greater than x > y
>= Greater than or equal to x >= y
< Less than x < y
<= Less than or equal to x <= y

We next branch the program into 3 separate directions depending on 3 mutually exclusive conditions.

x = 2
y = 4

if (x > y):
    print("X is greater than Y")
elif (x==y):
    print("X is equal to Y")
elif (x < y):
    print("X is smaller than Y")
X is smaller than Y
x <- 2
y <- 4

if (x > y) {
  cat("X is greater than Y\n")
} else if (x == y) {
  cat("X is equal to Y\n")
} else if (x < y) {
  cat("X is smaller than Y\n")
}
X is smaller than Y
Warning

Note the double equal symbol ==. This is a logical operator or a Boolean operator such as EQUAL, AND, OR, and NOT. While the single equal symbol = is an assignment operator (i.e., x = 3 assigns the value 3 to variable with name x), the double equal symbol is a logical operator. You can find more information about Boolean operators here: Wiki-Boolean Operators

The expression x == 3 for instance asks whether the content of variable x equals the value of 3. If it does, the statement returns True and if it does not, the statement returns False. In the field of Logic the state of True is often coded with the value 1 and the state of False is coded as the value 0. When you used dummy variables in econometrics you basically used a Boolean variable. A dummy variable is simply an indicator variable taking the value 0 or 1 to indicate whether a certain observation belongs to a specific category.

Here is an example to illustrate the difference between = and ==.

# Assign value 3 to variable with name x using singe equal symbol
x = 3
print(x)
3
# Check whether the value of variable x is 3?
print(x == 3)
True
# Check whether the value of variable x is 4?
print(x == 4)
False
# Assign value 3 to variable with name x using single equal symbol
x <- 3
cat("x =", x, "\n")
x = 3 
# Check whether the value of variable x is 3?
cat("x == 3 =", x == 3, "\n")
x == 3 = TRUE 
# Check whether the value of variable x is 4?
cat("x == 4 =", x == 4, "\n")
x == 4 = FALSE 

The elif (x==y) statement above checks whether the value of variable x is equal to the value of variable y at that particular point in your code (i.e., at runtime). If this is the case, the elif function returns the value 1 (which means True) and then executes the associated code block.

Here is another simple example using a branching if statement. We first draw some random number between 0 and 1 using the random() function. In order to use this function we first have to import the library in which this function is stored as it is not part of the core functions. We again use the import statement to import the random library. One of the functions in the random library is the function random() (yes it has the same name but there are other functions in the random library as well). In order to call the function random() we need to indicate the library name followed by a . (dot) and then the function name. So all in all this is: random.random() which will draw a random number between 0 and 1. We then check whether the number is smaller or larger than 0.5. For each eventuality we can then assign a string of commands to be executed.

import random

x = random.random()
if (x > 0.5):
    print("Random Number x= {:5.2f} is greater than 0.5".format(x))
else:
    print("Random Number x= {:5.2f} is smaller than or equal to 0.5".format(x))
Random Number x=  0.32 is smaller than or equal to 0.5
x <- runif(1)  # Generate a random number between 0 and 1
if (x > 0.5) {
  cat("Random Number x =", format(x, digits = 2), "is greater than 0.5\n")
} else {
  cat("Random Number x =", format(x, digits = 2), "is smaller than or equal to 0.5\n")
}
Random Number x = 0.033 is smaller than or equal to 0.5

We can also ask for more than one branching criteria again such as

import random

x = random.random()
if (x > 0.9):
    print("Random Number x= {:5.2f} is greater than 0.9".format(x))
elif (x > 0.8):
    print("Random Number x= {:5.2f} is greater than 0.8".format(x))
elif (x > 0.7):
    print("Random Number x= {:5.2f} is greater than 0.7".format(x))
else:
    print("Random Number x= {:5.2f} is smaller than or equal to 0.7".format(x))
Random Number x=  0.58 is smaller than or equal to 0.7
x <- runif(1)  # Generate a random number between 0 and 1

if (x > 0.9) {
  cat("Random Number x =", format(x, digits = 2), "is greater than 0.9\n")
} else if (x > 0.8) {
  cat("Random Number x =", format(x, digits = 2), "is greater than 0.8\n")
} else if (x > 0.7) {
  cat("Random Number x =", format(x, digits = 2), "is greater than 0.7\n")
} else {
  cat("Random Number x =", format(x, digits = 2), "is smaller than or equal to 0.7\n")
}
Random Number x = 0.2 is smaller than or equal to 0.7

Running the same script again, will result in a different random number being drawn, so that the result may differ of course.

import random

x = random.random()
if (x > 0.9):
    print("Random Number x= {:5.2f} is greater than 0.9".format(x))
elif (x > 0.8):
    print("Random Number x= {:5.2f} is greater than 0.8".format(x))
elif (x > 0.7):
    print("Random Number x= {:5.2f} is greater than 0.7".format(x))
else:
    print("Random Number x= {:5.2f} is smaller than or equal to 0.7".format(x))
Random Number x=  0.38 is smaller than or equal to 0.7
x <- runif(1)  # Generate a random number between 0 and 1

if (x > 0.9) {
  cat("Random Number x =", format(x, digits = 2), "is greater than 0.9\n")
} else if (x > 0.8) {
  cat("Random Number x =", format(x, digits = 2), "is greater than 0.8\n")
} else if (x > 0.7) {
  cat("Random Number x =", format(x, digits = 2), "is greater than 0.7\n")
} else {
  cat("Random Number x =", format(x, digits = 2), "is smaller than or equal to 0.7\n")
}
Random Number x = 0.77 is greater than 0.7

5.1.2 Branching with Logical Operators

Finally, we can use logical operators such as and as well as or to construct more sophisticated conditions for code branching. Assume, for instance, that you program a game that assigns a price of $1 if a random number is greater than 0.3 but less than 0.5. You could use the logical statement and to accomplish this as follows:

import random

x = random.random()
print("Random Number is x= {:5.2f}".format(x))
Random Number is x=  0.32
if (x > 0.3 and x < 0.5):
    print("You win a price of $1, congratulations!")
else:
    print("Sorry, you win nothing!")
You win a price of $1, congratulations!
x <- runif(1)  # Generate a random number between 0 and 1

cat("Random Number is x =", format(x, digits = 2), "\n")
Random Number is x = 0.25 
if (x > 0.3 && x < 0.5) {
  cat("You win a prize of $1, congratulations!\n")
} else {
  cat("Sorry, you win nothing!\n")
}
Sorry, you win nothing!

A different game could assign a price of $1 to a player if a randomly drawn number is less than 0.3 or greater than 0.5. If you want to program this game, you would use the logical operator or as:

import random

x = random.random()
print("Random Number is x= {:5.2f}".format(x))
Random Number is x=  0.94
if (x < 0.3 or x > 0.5):
    print("You win a price of $1, congratulations!")
else:
    print("Sorry, you win nothing!")
You win a price of $1, congratulations!
x <- runif(1)  # Generate a random number between 0 and 1

cat("Random Number is x =", format(x, digits = 2), "\n")
Random Number is x = 0.86 
if (x < 0.3 || x > 0.5) {
  cat("You win a prize of $1, congratulations!\n")
} else {
  cat("Sorry, you win nothing!\n")
}
You win a prize of $1, congratulations!

And you can of course combine these as well. A more complex game could pay the player $1 if the random number is at least 0.1 but less than two 0.2 or larger than 0.6. Notice that "at least 0.1" means that 0.1 is included in the condition so you need the >= symbol as opposed the strictly greater >. You could program this as:

import random

x = random.random()
print("Random Number is x= {:5.2f}".format(x))
Random Number is x=  0.18
if (x >= 0.1 and x < 0.2) or (x > 0.6):
    print("You win a price of $1, congratulations!")
else:
    print("Sorry, you win nothing!")
You win a price of $1, congratulations!
x <- runif(1)  # Generate a random number between 0 and 1

cat("Random Number is x =", format(x, digits = 2), "\n")
Random Number is x = 0.074 
if ((x >= 0.1 && x < 0.2) || (x > 0.6)) {
  cat("You win a prize of $1, congratulations!\n")
} else {
  cat("Sorry, you win nothing!\n")
}
Sorry, you win nothing!

5.2 For-Loops

5.2.1 Loop to Repeat a Simple Print Function

Assume you have the following assignment. Please print the following on a screen:

i = 0
i = 1
i = 2
i = 3

etc.

i = 9

We could first of course just write simple print statements as follows:

print('i = {}'.format(0))
print('i = {}'.format(1))
print('i = {}'.format(2))
print('i = {}'.format(3))
print('i = {}'.format(4))
print('i = {}'.format(5))
print('i = {}'.format(6))
print('i = {}'.format(7))
print('i = {}'.format(8))
print('i = {}'.format(9))
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
cat("i =", 0, "\n")
cat("i =", 1, "\n")
cat("i =", 2, "\n")
cat("i =", 3, "\n")
cat("i =", 4, "\n")
cat("i =", 5, "\n")
cat("i =", 6, "\n")
cat("i =", 7, "\n")
cat("i =", 8, "\n")
cat("i =", 9, "\n")
i = 0 
i = 1 
i = 2 
i = 3 
i = 4 
i = 5 
i = 6 
i = 7 
i = 8 
i = 9 

Not wrong, but pretty slow to produce and boring. Whenever a task is repetitive and boring there is probably a quicker and more exciting way of accomplishing it.

Let's think about a loop implementation. When you construct a loop, you essentially define a code block that gets repeated a number of times. Figure 5.2 illustrates the loop concept. An iterator variable var is generated and is assigned a “value” out of a collection of values such as a list or tuple. The latter is referred to as the iterable.

Figure 5.2: Loop Structure Illustration

Now try this in a code example that implements the exercise above again:

for i in range(10):
    print('i = {}'.format(i))
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
for (i in 0:9) {
  cat("i =", i, "\n")
}
i = 0 
i = 1 
i = 2 
i = 3 
i = 4 
i = 5 
i = 6 
i = 7 
i = 8 
i = 9 

Note that we again need to increment the print statement inside of the loop with 4! white-spaces. The range() command will generate a list with 10 objects in it. The objects are the numbers from [0,1,...9]. It will then instruct the computer to assign the list elements to variable i in each round.

You can then decide what to do with the specific value of variable i in each round. Variable i is called the iterator or counter as it changes its value in every iteration of the loop and in a way counts in which round you currently are. Here's a more elaborate example.

for i in range(10):
    x = i/2
    print('Round: {}'.format(i))
    print('------------------------')
    print('i = {}'.format(i))
    print('x = i/2 = {}/2 = {}'.format(i, x))
    print('------------------------')
Round: 0
------------------------
i = 0
x = i/2 = 0/2 = 0.0
------------------------
Round: 1
------------------------
i = 1
x = i/2 = 1/2 = 0.5
------------------------
Round: 2
------------------------
i = 2
x = i/2 = 2/2 = 1.0
------------------------
Round: 3
------------------------
i = 3
x = i/2 = 3/2 = 1.5
------------------------
Round: 4
------------------------
i = 4
x = i/2 = 4/2 = 2.0
------------------------
Round: 5
------------------------
i = 5
x = i/2 = 5/2 = 2.5
------------------------
Round: 6
------------------------
i = 6
x = i/2 = 6/2 = 3.0
------------------------
Round: 7
------------------------
i = 7
x = i/2 = 7/2 = 3.5
------------------------
Round: 8
------------------------
i = 8
x = i/2 = 8/2 = 4.0
------------------------
Round: 9
------------------------
i = 9
x = i/2 = 9/2 = 4.5
------------------------
for (i in 0:9) {
  x <- i/2
  cat("Round:", i, "\n")
  cat("------------------------\n")
  cat("i =", i, "\n")
  cat("x = i/2 =", i, "/2 =", x, "\n")
  cat("------------------------\n\n")
}
Round: 0 
------------------------
i = 0 
x = i/2 = 0 /2 = 0 
------------------------

Round: 1 
------------------------
i = 1 
x = i/2 = 1 /2 = 0.5 
------------------------

Round: 2 
------------------------
i = 2 
x = i/2 = 2 /2 = 1 
------------------------

Round: 3 
------------------------
i = 3 
x = i/2 = 3 /2 = 1.5 
------------------------

Round: 4 
------------------------
i = 4 
x = i/2 = 4 /2 = 2 
------------------------

Round: 5 
------------------------
i = 5 
x = i/2 = 5 /2 = 2.5 
------------------------

Round: 6 
------------------------
i = 6 
x = i/2 = 6 /2 = 3 
------------------------

Round: 7 
------------------------
i = 7 
x = i/2 = 7 /2 = 3.5 
------------------------

Round: 8 
------------------------
i = 8 
x = i/2 = 8 /2 = 4 
------------------------

Round: 9 
------------------------
i = 9 
x = i/2 = 9 /2 = 4.5 
------------------------

5.2.2 Loop to Calculate the Sum of Numbers

Here is another simple example. We first assign a list with values 0,1,2,3,4,5. We then "loop" through all the values of this list and print them one by one. In addition, we add up all the values of this list. The command for x in range(6) assigns x equal to each value of 0,1, ...,5 one by one and we can then use x itself in each iteration.

Note that if you want a list from 0,1,...,5 you need to define the range command with range(6). Using this loop we can step through all the values of our list and assign certain operations to each value.

# Summation variable starting with zero value
sumx = 0

# Start loop
for x in range(6):
    sumx = sumx + x  # adds up the elements from 0 to 5
    print("x = {}".format(x))
    print("sum(x) = {}".format(sumx))
x = 0
sum(x) = 0
x = 1
sum(x) = 1
x = 2
sum(x) = 3
x = 3
sum(x) = 6
x = 4
sum(x) = 10
x = 5
sum(x) = 15
# Summation variable starting with zero value
sumx <- 0

# Start loop
for (x in 0:5) {
  sumx <- sumx + x  # adds up the elements from 0 to 5
  cat("x =", x, "\n")
  cat("sum(x) =", sumx, "\n")
}
x = 0 
sum(x) = 0 
x = 1 
sum(x) = 1 
x = 2 
sum(x) = 3 
x = 3 
sum(x) = 6 
x = 4 
sum(x) = 10 
x = 5 
sum(x) = 15 

In the above code snipped the x variable is the counter and the sumx variable is the accumulator. The accumulator sums up the iterator in each round and adds it to the already accumulated sum of previous iterations.

Note

An alternative, shorter, notation that is often used for accumulator type variables is sumx += x which is short for sumx = sumx + x

# Summation variable starting with zero value
sumx = 0

# Start loop
for x in range(6):
    sumx += x  # adds up the elements from 0 to 5
    print("x = {}".format(x))
    print("sum(x) = {}".format(sumx))
x = 0
sum(x) = 0
x = 1
sum(x) = 1
x = 2
sum(x) = 3
x = 3
sum(x) = 6
x = 4
sum(x) = 10
x = 5
sum(x) = 15

This style is not available in R.

Warning

It is bad programming style if you re-assign the iterator variable x within the code block that gets repeated and you should avoid it. Some programming languages will not even allow you to assign a value to an iterator within a loop statement.

5.2.3 Loop to Calculate the Product of Numbers

Here is another example. We write a loop that calculates the factorial of a number: \(3!\). Remember that \(3! = 1 * 2 * 3\). In order to make this happen we write a loop that sets \(i = 1, 2,\) and 3 and multiplies it with the product of the previous round. The variable n_fac stores the product from each round.

n = 6
n_fac = 1

for i in range(n):
    print("i = ", i)
    n_fac = n_fac * (i+1)

print("The factorial of {} is: {}".format(n, n_fac))
i =  0
i =  1
i =  2
i =  3
i =  4
i =  5
The factorial of 6 is: 720
n <- 6
n_fac <- 1

for (i in 0:(n-1)) {
  cat("i =", i, "\n")
  n_fac <- n_fac * (i+1)
}

cat("The factorial of", n, "is:", n_fac, "\n")
i = 0 
i = 1 
i = 2 
i = 3 
i = 4 
i = 5 
The factorial of 6 is: 720 

Using a different method we can also calculate the factorial as: Here the accumulator variable n_fac is not accumulating a sum of numbers but a product.

import math as m
print("The factorial of 6 is {}".format(m.factorial(6)))
The factorial of 6 is 720
Error in library(gmp): there is no package called 'gmp'
cat("The factorial of 6 is", factorial(6), "\n")
The factorial of 6 is 720 

5.2.4 Loop with Iterator Values Not Starting at Zero

If you use the range(5) command in the previous example, Python will generate an internal list with the values [0,1,2,3,4] and then let the loop run through the values of this list so that the iterator variable will start with value 0, then increment to value 1 in the second round, then increment to 3 in the third round and so on.

If you want the iterator variable of the loop to take on certain values and not start from 0 you can specify the range command slightly differently and give it a new starting value such as range(3, 6) would generate an internal list of [3,4,5] and then let the iterator variable run through that list in each round of the loop.

Note

Python uses half open intervals in its internal list generation processes. This means that the interval you hand into the range command in mathematical notation is \[[3,6)\]. This means it’s closed at the bottom and open on top. Closed at the bottom means that the number 3 is included in the interval and open on top means that the number 6 is excluded from the interval.

Here is an example of a loop where the iterator variable does not start with value zero.

for i in range(3,6):
    print('i = {}'.format(i))
i = 3
i = 4
i = 5
for (i in 3:5) {
  cat("i =", i, "\n")
}
i = 3 
i = 4 
i = 5 

5.2.5 Nested Loops

In this section you will see an example of a loop inside a loop, or a nested loop.

for i in range(3,6):
    print('Inside first loop but outside second loop i = {}'.format(i))

    for j in range(100, 105):
        print('Inside second loop: i = {} and j = {}'.format(i,j))
Inside first loop but outside second loop i = 3
Inside second loop: i = 3 and j = 100
Inside second loop: i = 3 and j = 101
Inside second loop: i = 3 and j = 102
Inside second loop: i = 3 and j = 103
Inside second loop: i = 3 and j = 104
Inside first loop but outside second loop i = 4
Inside second loop: i = 4 and j = 100
Inside second loop: i = 4 and j = 101
Inside second loop: i = 4 and j = 102
Inside second loop: i = 4 and j = 103
Inside second loop: i = 4 and j = 104
Inside first loop but outside second loop i = 5
Inside second loop: i = 5 and j = 100
Inside second loop: i = 5 and j = 101
Inside second loop: i = 5 and j = 102
Inside second loop: i = 5 and j = 103
Inside second loop: i = 5 and j = 104
for (i in 3:5) {
  cat("Inside first loop but outside second loop i =", i, "\n")

  for (j in 100:104) {
    cat("Inside second loop: i =", i, "and j =", j, "\n")
  }
}
Inside first loop but outside second loop i = 3 
Inside second loop: i = 3 and j = 100 
Inside second loop: i = 3 and j = 101 
Inside second loop: i = 3 and j = 102 
Inside second loop: i = 3 and j = 103 
Inside second loop: i = 3 and j = 104 
Inside first loop but outside second loop i = 4 
Inside second loop: i = 4 and j = 100 
Inside second loop: i = 4 and j = 101 
Inside second loop: i = 4 and j = 102 
Inside second loop: i = 4 and j = 103 
Inside second loop: i = 4 and j = 104 
Inside first loop but outside second loop i = 5 
Inside second loop: i = 5 and j = 100 
Inside second loop: i = 5 and j = 101 
Inside second loop: i = 5 and j = 102 
Inside second loop: i = 5 and j = 103 
Inside second loop: i = 5 and j = 104 

As you can see the first loop gets executed and the iterator variable i takes on value 3. Then the code jumps to the "inside" loop and executes the repetitions for iterator variable j.

5.2.6 Looping through the Content of a List using Indexing

Finally, here is an example where we loop through the values of a list again. In each round we "grab" a number from the list and print it.

Let's first define a list with some numbers in it.

xv = list(range(5))
print("xv= {}".format(xv))
xv= [0, 1, 2, 3, 4]
xv <- 0:4
cat("xv =", xv, "\n")
xv = 0 1 2 3 4 

We now start the loop and pick each value of this list one-by-one. The command length tells us how many arguments are in the list xv and then lets the loop run from 1 to the total number of arguments in xv. Note also the difference in the two print commands, where the second one results in formatted output.

xv = list(range(6))
for i in range(len(xv)):
    print("i= {}".format(i))
    print("xv[i]= {:4.2f}".format(xv[i]))
i= 0
xv[i]= 0.00
i= 1
xv[i]= 1.00
i= 2
xv[i]= 2.00
i= 3
xv[i]= 3.00
i= 4
xv[i]= 4.00
i= 5
xv[i]= 5.00
xv <- 0:5
for (i in 1:length(xv)) {
  cat("i =", i - 1, "\n")
  cat("xv[i] =", format(xv[i], digits = 2), "\n")
}
i = 0 
xv[i] = 0 
i = 1 
xv[i] = 1 
i = 2 
xv[i] = 2 
i = 3 
xv[i] = 3 
i = 4 
xv[i] = 4 
i = 5 
xv[i] = 5 

5.2.7 Looping through the Content of a List without Indexing

If you already have a list predefined and you want to loop through the content of that list you can use a for loop in a more direct way without explicitly indexing the list elements inside of brackets [].

# Define the list
myList = ['jim', 'james', 23, 12, 'car', 'bike']

for x in myList:
    print('indexing variable x is: ', x)
indexing variable x is:  jim
indexing variable x is:  james
indexing variable x is:  23
indexing variable x is:  12
indexing variable x is:  car
indexing variable x is:  bike
myList <- c('jim', 'james', 23, 12, 'car', 'bike')

for (x in myList) {
  cat("indexing variable x is:", x, "\n")
}
indexing variable x is: jim 
indexing variable x is: james 
indexing variable x is: 23 
indexing variable x is: 12 
indexing variable x is: car 
indexing variable x is: bike 

If you need to keep track of the position of the various items in the list you can use the enumerate command which internally generates a "zipped list" that pairs up each element in the list with its index inside of the list. Here is an example using the previous list:

# Define the list
myList = ['jim', 'james', 23, 12, 'car', 'bike']

for i, x in enumerate(myList):
    print('variable i is: {} and x is: {}'.format(i, x))
variable i is: 0 and x is: jim
variable i is: 1 and x is: james
variable i is: 2 and x is: 23
variable i is: 3 and x is: 12
variable i is: 4 and x is: car
variable i is: 5 and x is: bike
myList <- c('jim', 'james', 23, 12, 'car', 'bike')

for (i in 1:length(myList)) {
  x <- myList[i]
  cat("variable i is:", i - 1, "and x is:", x, "\n")
}
variable i is: 0 and x is: jim 
variable i is: 1 and x is: james 
variable i is: 2 and x is: 23 
variable i is: 3 and x is: 12 
variable i is: 4 and x is: car 
variable i is: 5 and x is: bike 

5.2.8 Combining Lists and Looping Through Them

If you have two or more lists that you want to loop through simultaneously pulling the first elements from both lists (in tandem), followed by the second elements from both lists, etc. you can use the zip command. The zip function "glues" or "zips" the lists together and then allows you to run (or loop) through them in this pairwise fashion. The next example illustrates this.

# Define the list of spouses
myMaleList = ['jim', 'james', 'jack', 'john', 'jason']
myFemaleList = ['emma', 'clara', 'susan', 'jill', 'lisa']

for husband, wife in zip(myMaleList, myFemaleList):
    print('The hubby is: {} and the wife is {}'.format(husband, wife))
The hubby is: jim and the wife is emma
The hubby is: james and the wife is clara
The hubby is: jack and the wife is susan
The hubby is: john and the wife is jill
The hubby is: jason and the wife is lisa
myMaleList <- c('jim', 'james', 'jack', 'john', 'jason')
myFemaleList <- c('emma', 'clara', 'susan', 'jill', 'lisa')

for (i in 1:length(myMaleList)) {
  husband <- myMaleList[i]
  wife <- myFemaleList[i]
  cat("The hubby is:", husband, "and the wife is", wife, "\n")
}
The hubby is: jim and the wife is emma 
The hubby is: james and the wife is clara 
The hubby is: jack and the wife is susan 
The hubby is: john and the wife is jill 
The hubby is: jason and the wife is lisa 

If you want to combine this with the index of the names inside the lists you can use enumerate again. Be careful in how you use the parenthesis around the variables husband and wife in the for loop construct.

# Define the list of spouses
myMaleList = ['jim', 'james', 'jack', 'john', 'jason']
myFemaleList = ['emma', 'clara', 'susan', 'jill', 'lisa']

for i, (husband, wife) in enumerate(zip(myMaleList, myFemaleList)):
    print("""At index: {} the hubby is: {}
    and the wife is {}""".format(i, husband, wife))
At index: 0 the hubby is: jim
    and the wife is emma
At index: 1 the hubby is: james
    and the wife is clara
At index: 2 the hubby is: jack
    and the wife is susan
At index: 3 the hubby is: john
    and the wife is jill
At index: 4 the hubby is: jason
    and the wife is lisa
myMaleList <- c('jim', 'james', 'jack', 'john', 'jason')
myFemaleList <- c('emma', 'clara', 'susan', 'jill', 'lisa')

for (i in 1:length(myMaleList)) {
  husband <- myMaleList[i]
  wife <- myFemaleList[i]
  cat("At index:", i - 1, "the hubby is:", husband, "\n")
  cat("and the wife is", wife, "\n\n")
}
At index: 0 the hubby is: jim 
and the wife is emma 

At index: 1 the hubby is: james 
and the wife is clara 

At index: 2 the hubby is: jack 
and the wife is susan 

At index: 3 the hubby is: john 
and the wife is jill 

At index: 4 the hubby is: jason 
and the wife is lisa 

5.3 While Loop

The while loop runs and keeps repeating to do something until a certain stopping condition is met.

5.3.1 While Loop 1

In the first example we let the iterations run as long as the value of variable x is smaller than 10. In every iteration we increase x by one unit, so that in effect the loop gets repeated 9 times.

In a while loop the iterator variable is not automatically incremented as in the for loop, where we explicitly state the starting and stopping values for the iterator variable. We therefore have to make sure that we increment the iterator/counter variable x within the repeatable codeblock using x = x +1 or shorter and more efficiently x += 1.

x = 0
y = 0
while (x < 10):
    y = y + x
    print("X= {} and Y= {}".format(x, y))
    x += 1  # i.e., x = x + 1
X= 0 and Y= 0
X= 1 and Y= 1
X= 2 and Y= 3
X= 3 and Y= 6
X= 4 and Y= 10
X= 5 and Y= 15
X= 6 and Y= 21
X= 7 and Y= 28
X= 8 and Y= 36
X= 9 and Y= 45
x <- 0
y <- 0

while (x < 10) {
  y <- y + x
  cat("X =", x, "and Y =", y, "\n")
  x <- x + 1
}
X = 0 and Y = 0 
X = 1 and Y = 1 
X = 2 and Y = 3 
X = 3 and Y = 6 
X = 4 and Y = 10 
X = 5 and Y = 15 
X = 6 and Y = 21 
X = 7 and Y = 28 
X = 8 and Y = 36 
X = 9 and Y = 45 

The accumulator variable y calculates the cumulative sum of all numbers from 1 to 9, so that \(y = 0+1+2+...+9\). If you forget the statement that increments the counter at the end of the repeatable code block within the loop, then the loop will run infinitely long and you have to break the code with pressing ctrl + c which will stop the execution of the Python script.

5.3.2 While Loop 2

In this last example we calculate how long it takes to repay a loan. The longer you wait to repay the loan, the more interest is accumulated and added to the outstanding debt. The key formula in this example is:

\[\text{debt}_\text{tomorrow} = \text{debt}_\text{today} \times (1 + \text{interest rate}) - \text{payments}_\text{today}\]

r = 0.11  # Annual interest rate
# Time between repayments in years (i.e., monthly repayments)
period = 1.0/12.0
debt_initial = 1000.0  # Initial debt
payments = 12.0  # Amount repaid each period

mytime = 0
debt = debt_initial
while (debt > 0):
    mytime = mytime + period
    debt = debt*(1. + r*period) - payments

print("Loan will be repaid in: {} years.".format(mytime))
Loan will be repaid in: 13.250000000000025 years.
r <- 0.11  # Annual interest rate
period <- 1.0/12.0
debt_initial <- 1000.0
payments <- 12.0

mytime <- 0
debt <- debt_initial

while (debt > 0) {
  mytime <- mytime + period
  debt <- debt * (1 + r * period) - payments
}

cat("Loan will be repaid in:", mytime, "years.\n")
Loan will be repaid in: 13.25 years.

5.4 Combining Branching Statements and Loops

We can of course combine everything we have learned so far. Let's assume you have the following programming task. You have to generate a list with numbers from 1 to 20. You then have to collect all numbers from 1 to 10 in a blue bin and add them up. All numbers from 11 to 20 are to be added up in the bin. How would you do that?

You use a loop that runs through all the numbers of a list and combine it with a branching statement that checks whether a number is smaller than 11. If YES (i.e., numbers are smaller 11) execute one block of code where the numbers are collected in a blue bin and if NO (i.e., numbers are greater 10) then put those numbers into the red bin.

Here is the example code that would accomplish this.

blueBin = 0
redBin = 0

for i in range(1,21):
    if i <= 10:
        print('Number i = {:2d} will be put in BLUE bin'.format(i))
        blueBin = blueBin + i
    else:
        print('Number i = {:2d} will be put in RED bin'.format(i))
        redBin = redBin + i
print(' ')
print('------------------------------------------- ')
print('The sum of numbers in BLUE bin is {}'.format(blueBin))
print('The sum of numbers in RED  bin is {}'.format(redBin))
print('------------------------------------------- ')
Number i =  1 will be put in BLUE bin
Number i =  2 will be put in BLUE bin
Number i =  3 will be put in BLUE bin
Number i =  4 will be put in BLUE bin
Number i =  5 will be put in BLUE bin
Number i =  6 will be put in BLUE bin
Number i =  7 will be put in BLUE bin
Number i =  8 will be put in BLUE bin
Number i =  9 will be put in BLUE bin
Number i = 10 will be put in BLUE bin
Number i = 11 will be put in RED bin
Number i = 12 will be put in RED bin
Number i = 13 will be put in RED bin
Number i = 14 will be put in RED bin
Number i = 15 will be put in RED bin
Number i = 16 will be put in RED bin
Number i = 17 will be put in RED bin
Number i = 18 will be put in RED bin
Number i = 19 will be put in RED bin
Number i = 20 will be put in RED bin
 
------------------------------------------- 
The sum of numbers in BLUE bin is 55
The sum of numbers in RED  bin is 155
------------------------------------------- 
blueBin <- 0
redBin <- 0

for (i in 1:20) {
  if (i <= 10) {
    cat("Number i =", i, "will be put in BLUE bin\n")
    blueBin <- blueBin + i
  } else {
    cat("Number i =", i, "will be put in RED bin\n")
    redBin <- redBin + i
  }
}
cat("\n")
cat("-------------------------------------------\n")
cat("The sum of numbers in BLUE bin is", blueBin, "\n")
cat("The sum of numbers in RED bin is", redBin, "\n")
cat("-------------------------------------------\n")
Number i = 1 will be put in BLUE bin
Number i = 2 will be put in BLUE bin
Number i = 3 will be put in BLUE bin
Number i = 4 will be put in BLUE bin
Number i = 5 will be put in BLUE bin
Number i = 6 will be put in BLUE bin
Number i = 7 will be put in BLUE bin
Number i = 8 will be put in BLUE bin
Number i = 9 will be put in BLUE bin
Number i = 10 will be put in BLUE bin
Number i = 11 will be put in RED bin
Number i = 12 will be put in RED bin
Number i = 13 will be put in RED bin
Number i = 14 will be put in RED bin
Number i = 15 will be put in RED bin
Number i = 16 will be put in RED bin
Number i = 17 will be put in RED bin
Number i = 18 will be put in RED bin
Number i = 19 will be put in RED bin
Number i = 20 will be put in RED bin

-------------------------------------------
The sum of numbers in BLUE bin is 55 
The sum of numbers in RED bin is 155 
-------------------------------------------

5.5 Time Your Work

Sometimes it is useful to know how long it takes for a script to run through. In order to accomplish this you can use the time() function from the time library. When you call it, it gives you the current time. You would therefore call the time function at the beginning of your script and store that value in some variable, say tic. This is followed by your "main code" that works through a series of commands. At the end of the script you call for the current time again and store it in a variable, say, toc. Then you simply take the difference between tic and toc variable and you'll have your elapsed time period. Here's an example that times a "large" while loop.

import time  # Imports system time module to time your script
tic = time.time()

x = 0
while (x < 1000000):
    # add some stuff that needs to be calculated, e.g.
    y = y + x
    x += 1

toc = time.time()
print("Time elapsed = {} seconds".format(toc - tic))
Time elapsed = 0.10620260238647461 seconds
tic <- Sys.time()

x <- 0
y <- 0
while (x < 1000000) {
  # add some stuff that needs to be calculated, e.g.
  y <- y + x
  x <- x + 1
}

toc <- Sys.time()
cat("Time elapsed =", as.numeric(toc - tic), "seconds\n")
Time elapsed = 0.03648233 seconds
Key Concepts and Summary
  • A branching statement allows you to split your code into alternative execution blocks.
  • A loop statement allows you to execute code blocks repeatedly.
  • You can nest loops inside of each other and you can nest branching statements as well.
  1. Generate a list with entries from 14 to 40 with stepsize 2.
  2. Write a loop that divides the first 10 entries of your list above by 5 3. Write a loop that replaces all the elements of your list with elements that are half a big. If you list says [1,2,3,4] your new list should read [0.5,1,1.5,2].