Loops

2 minute read

  • Write functions with for and while loops
  • Know when to write loops, and when to use vectorized functions or lapply and related functions

live notes

Announcements:

  • Midterm review video assignment is live.

for loops

for loops are used to iterate through vectors, for example:

for(i in 1:5){
    print(i^2)
}

The general form is:

for(VAR in SEQ){
    RUN THIS BLOCK OF CODE
}

It’s approximately equivalent to:

VAR = SEQ[[1]]
RUN CODE

VAR = SEQ[[2]]
RUN CODE

...

VAR = SEQ[[length(SEQ)]]
RUN CODE

Alternatives to for loops

Suppose we want to compute the result of log applied to several elements in a vector. We can always do it in a for loop:

x = 1:5
ans = rep(NA, length(x))
for(i in seq_along(x)){
    ans[i] = log(x[i])
}

log is vectorized. Instead of explicitly looping, we can just do:

log(x)

That is, vectorized functions implicitly loop over their elements, and apply functions elementwise. You could even take this as the definition of a vectorized function.

If a vectorized function is not available, then we can still loop through lapply and sapply. The s in sapply is for “simplify” to a vector.

sapply(x, log)

When to use loops

Use explicit loops when there is true loop carried data dependence. This means that what we do in one iteration of the loop affects what we do in a later iteration. lapply and friends cannot handle this case.

A classic example is calculating the Fibonacci sequence.

n = 10
a = 0
b = 1
for(i in seq(n)){
    apb = a + b
    a = b
    b = apb
}

Here a and b represent the two most recently calculated numbers in the Fibonacci sequence. With every iteration we compute the next number, apb, by adding a and b, and then set a and b to the most recently calculated numbers.

while loops

while loops are the other common looping construct. Like if statements, they test for a condition.

n = 0
while(n < 5){
    print(n)
    n = n + 1
}

The general form is:

while(CONDITION IS TRUE){
    RUN THIS BLOCK OF CODE
}

This is approximately equivalent to:

if(CONDITION IS TRUE){
    RUN THIS BLOCK OF CODE
} else if(CONDITION IS TRUE){
    RUN THIS BLOCK OF CODE
} else if(CONDITION IS TRUE){
    ...
}   ... continuing forever

break and return

Sometimes it’s useful to break out of a loop early. Here’s an example:

for(i in 1:10){
    print(i)
    if(i == 5){
        break
    }
}

Here’s a more compelling example in the context of our roulette martingale example. Suppose we would like to look at the histogram of the number of times you can play with this strategy until you’re broke.

times_played_until_broke = function(maxplays = 1e4, money = 5000, initialbet = 10){
    bet = initialbet
    for(i in seq(maxplays)){
        win = sample(c(TRUE, FALSE), size = 1, prob = c(18, 19)/37)
        if(win){
            money = money + bet
            bet = initialbet
        } else {
            money = money - bet
            if(money <= 0){
                # Once we have no money left, there's no need to keep going.
                break
                # Alternatively:
                # return(i)
            }
            bet = 2 * bet
        }
    }
    i
}

x = replicate(500L, times_played_until_broke())

hist(x)

The way we’ve written this, the value 10,000 actually means “more than 10,000 plays”. We can still look at the quantiles to get an idea of how many times we could play like this:

quantile(x)

Exercise: Change the above function to use a while loop.

Updated: