Loops
- Write functions with
for
andwhile
loops - Know when to write loops, and when to use vectorized functions or
lapply
and related functions
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.