Control structures

As with most programming languages, R has various means of controlling the flow of computation during the course of a computation. These take the form of condition statements and “loops”.

Exercise 1

Execute the following in your jupyter notebook.

?Control

This should provide you with some useful information regarding the constructs used for execution control in R. But here are some more details.

Conditional execution

The basic control statement is if. It has this general structure.

if (condition)
{
   statement  
} else
{
   alternative
}

The condition part should evaluate to a single boolean value (or values that can be coerced to a boolean value, such as 0 and 1). The boolean value can be the result of having evaluated an expression, such as 1 < 2, and as such, can include boolean operators such as

  • x == y “x is equal to y”

  • x != y “x is not equal to y”

  • x > y “x is greater than y”

  • x < y “x is less than y”

  • x <= y “x is less than or equal to y”

  • x >= y “x is greater than or equal to y”

For example,

if(TRUE)
{
    print("This is true")   
}
x <- 2 
if(x==3)
{
    print("This is true")
} else
{
    print("This is false")
}
y <- 4 
if(x==2 && y>2)
{
    print("x equals 2 and y is greater than 2")
}
[1] "This is true"
[1] "This is false"
[1] "x equals 2 and y is greater than 2"

The else part can contain another if, and if statements can be nested.

x<-6
if(x < 6)
{
   if(x > 2)
   {
       print("hello")
   } else
   {
       print("dag")
   }
} else if(x > 20)
{
    print("bonjour")
} else
{
    print("nuqneH")
}
[1] "nuqneH"

Note what happens if the expression has dimension greater than 1.

if(c(T,F)) 
{ 
    print("blob")
}
Warning message in if (c(T, F)) {:
“the condition has length > 1 and only the first element will be used”
[1] "blob"

The ifelse command takes as first argument the condition, as second argument the treatment if the condition is true and as third argument the treatment if the condition is false. In that case, the condition can be a vector. For instance we generate a sequence from 1 to 10 and we want to display values which are lower than 5 and greater than 8.

x <- 1:10 
ifelse(x<5 | x>8, x, 0)
  1. 1
  2. 2
  3. 3
  4. 4
  5. 0
  6. 0
  7. 0
  8. 0
  9. 9
  10. 10

Loops

R provides three ways to write loops: for, repeat and while. The for statement is excessively simple. You simply have to define index (here k) and a vector (in the example below the vector is 1:5) and you specify the action you want between braces.

for (k in 1:5)
{
   print(k)
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5

Exercise 2

What is going to happen here ? Check your answer in your own notebook.

for (k in 1:5)
{
   k <- 7
   print(k)
}
[1] 7
[1] 7
[1] 7
[1] 7
[1] 7

When it is not possible to use the for statement, you can also use break or while by specifying a breaking rules. One should be careful with this kind of loops since if the breaking rules is misspecified the loop will never end. In the two examples below the standard normal distribution is drawn in as long as the value is lower than 1. The cat() function is used to display the present value on screen.

repeat 
{ 
   g <- rnorm(1) 
   if (g > 1.0) break 
   cat(g,"\n")
} 
-0.8111026 
0.2837968 
-1.057219 
0.5092576 
0.003827784 
-0.03940056 
g <- 0
while (g < 1)
{
   g <- rnorm(1) 
   cat(g,"\n")
}
0.4330584 
-0.2053385 
0.5223292 
-0.3015243 
0.2309511 
1.045413 

Exercise 3

What criterion would you choose between using a repeat or a while ?

Map Reduce

Map and Reduce examples of a concept often refered to as a Higher Order Functions. This soundes rather impressive, however, this just means they are functions which can take functions as arguments and/or return a function.

Exercise 4

What do you think the output of the following code is ?

X<-c(1,2,3,4)
Y<-Map(sin,X)
print(Y)
[[1]]
[1] 0.841471

[[2]]
[1] 0.9092974

[[3]]
[1] 0.14112

[[4]]
[1] -0.7568025

Exercise 5

Using one sentence, can you explain what the “Higher Order Function” Map does ?

Map takes a fuction and a vector (or list) of values, and returns a list contaning the values of the function applied to each element of the vector or list.

Exercise 6

Predict what output the following code will produce.

X<-list(4,27,4^4)
Y<-list(2,3,4)
Z<-Map(log,X,Y)
print(Z)
[[1]]
[1] 2

[[2]]
[1] 3

[[3]]
[1] 4

Exercise 7

Predict what output the following code will produce.

X<-list(1,2,3,4)
Y<-list(4,5,6,7)
Z<-Map("+",X,Y)
print(Z)
[[1]]
[1] 5

[[2]]
[1] 7

[[3]]
[1] 9

[[4]]
[1] 11

Exercise 8

What do you think the output of the following code is ?

X<-list(1,2,3,4,5)
Y<-Reduce("*",X)
print(Y)
[1] 120

Exercise 9

What do you think the output of the following code is ?

X<-list(1,2,3,4,5)
Y<-Reduce("*",X,5)
print(Y)
[1] 600

Exercise 10

Can you explain what the “Higher Order Function” Reduce does ?

Reduce takes a function of two arguments and a vector (or list) of values and returns the value obtained by recursivley applying the function to the values in the vector (or list) and the previous result of the application of the function. An initial value can be specified if necessary.

Exercise 11

In which direction does Reduce traverse its sequence of input values ?

Exerise 12

Reduce can accumulate the results of applying the function. Use help to find out how and give an example showing how it is done.

X<-list(1,2,3,4)
Y<-Reduce("*",X,accumulate=TRUE)
print(Y)
[1]  1  2  6 24