Program Flow

Program Flow#

Without controls, a program will simply run from top to bottom, performing each command in turn. This would mean writing a lot of code if you wanted to perform the same set of actions on multiple different sets of data. Here we will learn how to control which parts of a program execute with if, and how to perform repetitive actions with the for loop.

The if function#

An if function performs a logical test – is something TRUE? – and then runs commands if the test is passed.

# If function
x <- 4
if(x >= 0){
    y = sqrt(x)
}
y # = 2

Here, we only want to calculate the square root of x if x is positive.

We can extend the use of if to include a block of code to execute if something is FALSE.

# If / Else
x <- -2
if(x >= 0){
    y = sqrt(x)
}else{
    cat("The result would be a complex number!")
}
# The result would be a complex number!"

You can go further by making if dependent on multiple logic statements, or use recursive if statements.

# Only allow integer square roots
x <- 4.2
if((x >= 0) & (x%%1==0)){
    y = sqrt(x)
}else{
    cat("The result would not be an integer!")
}

# Alternative method
if(x >= 0){
    if(x%%1==0){
        y = sqrt(x)
    }else{
        cat("The result would not be an integer!")
    }
}else{
    cat("The result would be a complex number!")
}

Exercise 0.9

  • In the script window, copy the first if statement above and execute it. You should get the correct result, 2.

  • Now make x a negative value and execute the script again, what happens?

  • Add an else statement to your script as in the second example above and test it.

  • Using either multiple logic statements or nested if statements, write a script that tests whether x is an even square number.

# Script to determine is x is a square number
if(x%%2==0){
   y = sqrt(x)
   if(y%%1==0){
      cat(paste(x,"is even and the square of",y))
   }else{
      cat(paste(x,"is not a square number"))
   }
}else{
   cat(paste(x,"is not an even number"))
}

# Test it for yourself with different values of x!

The for loop#

Whilst it’s very simple to run basic calculations on a vector or matrix of data, more sophisticated code is required for data.frames or when you want to perform complex functions on individual pieces of data.

The for loop is a basic programming concept that runs a series of commands through each loop, with one variable changing each time, which may or may not be used in the loop’s code. For instance we could loop through the numbers 1 to 10 if we wanted to perform an action 10 times, or if we wanted to use the numbers 1 to 10 each in the same calculation.

# A basic for loop
for(i in 1:10){
    cat("Loop!")
}
# Loop!Loop!Loop!Loop!Loop!Loop!Loop!Loop!Loop!Loop!

# A loop involving the loop variable
for(i in 1:10){
    cat(paste("Loop",i,"!"))
}
# Loop 1 !Loop 2 !Loop 3 !Loop 4 !Loop 5 !Loop 6 !Loop 7 !Loop 8 !Loop 9 !Loop 10 !

These are simple examples and don’t capture the results of the loop. If we want to store our results, we have to declare a variable ahead of time to put them into.

# A loop that gets results
data(EuStockMarkets)
plot(EuStockMarkets[,1])
movingAverage <- vector()
for(i in 1:length(EuStockMarkets[,1])){
    movingAverage[i] <- mean(EuStockMarkets[i:(i+29),1])
}
plot(movingAverage)

Note that an error was produced because when we reach the end of the time series, the data points we ask for don’t exist – we could adjust our loop to account for this by reducing the number of times we go through the loop so that we don’t reach past the end of the data.

Also, rather than refer to the pieces of data directly, we are using i to keep track of the index of the data we want to work with. This allows us to refer to data by its index, and therefore slice a moving section of data. In other circumstances, you can of course refer to items by their names.

Exercise 0.10

  • Write a for loop that prints out a countdown from 10 to 1.

# Countdown
for(i in 10:1){
   cat(i)
 }
 cat("Blast off!")
  • Using the EuStockMarkets data, make a plot of the FTSE data. Note that this data is not a data.frame but a time.series - you can find out more with ?ts.

# Plot FTSE data
data(EuStockMarkets)
plot(EuStockMarkets[,"FTSE"])
# Note that the $ syntax does not work with time.series objects
  • Using a for loop, calculate a moving average and make a corresponding vector of time points with the centres of each average.

# Calculate the moving average
movingAverage <- c()
for(i in 1:(length(EuStockMarkets[,"FTSE"])-29)){
   # Note that we avoid the error from earlier
   movingAverage[i] <- mean(EuStockMarkets[i:(i+29),"FTSE"])
}
times <- time(EuStockMarkets)[15:(length(EuStockMarkets[,"FTSE"])-15)]
  • Add the moving average to the plot using the lines function.

# Add to the plot
plot(EuStockMarkets[,"FTSE"])
lines(times,movingAverage,col=2)