Gaston Sanchez
- Why do you need loops?
- Get to know the For loop
- Get to know the While loop
- Get to know the Repeat loop
- Many times we need to perform a procedure several times
- We perform the same operation several times as long as some condition is fulfilled
- For this purpose we use loops
- The main idea is that of iteration
- R provides three basic paradigms:
for
,repeat
,while
Consider a numeric vector with prices of five items:
prices <- c(2.50, 2.95, 3.45, 3.25)
prices
## [1] 2.50 2.95 3.45 3.25
Say you are interested in printing each price individually. You can manually display them one by one, by typing the same command several times:
cat("Price 1 is", prices[1])
cat("Price 2 is", prices[2])
cat("Price 3 is", prices[3])
cat("Price 4 is", prices[4])
## Price 1 is 2.5
## Price 2 is 2.95
## Price 3 is 3.45
## Price 4 is 3.25
Or you can use a loop structure in which you tell the computer to display the prices a given number of times, but using one command instead of typing it various times:
for (i in 1:4) {
cat("Price", i, "is", prices[i], "\n")
}
## Price 1 is 2.5
## Price 2 is 2.95
## Price 3 is 3.45
## Price 4 is 3.25
Let’s make it less simple by creating a vector of prices with the names of the associated coffees:
coffee_prices <- c(
expresso = 2.50,
latte = 2.95,
mocha = 3.45,
cappuccino = 3.25)
coffee_prices
## expresso latte mocha cappuccino
## 2.50 2.95 3.45 3.25
Without using a loop, you can display, via cat()
, the prices
one-by-one; (this, of course, involves a lot of repetition)
cat("Expresso has a price of", coffee_prices[1])
cat("Latte has a price of", coffee_prices[2])
cat("Mocha has a price of", coffee_prices[3])
cat("Capuccino has a price of", coffee_prices[4])
## Expresso has a price of 2.5
## Latte has a price of 2.95
## Mocha has a price of 3.45
## Capuccino has a price of 3.25
for (i in 1:4) {
cat(names(coffee_prices)[i], "has a price of",
prices[i], "\n")
}
## expresso has a price of 2.5
## latte has a price of 2.95
## mocha has a price of 3.45
## cappuccino has a price of 3.25
- Often we want to repeatedly carry out some computation a fixed number of times.
- For instance, repeat an operation for each element of a vector.
- In R this can be done with a
for
loop. for
loops are used when we know exactly how many times we want the code to repeat
The anatomy of a for
loop is as follows:
for (iterator in times) {
do_something
}
for()
takes an iterator variable and a vector of times to
iterate through.
value <- 2
for (i in 1:5) {
value <- value * 2
print(value)
}
## [1] 4
## [1] 8
## [1] 16
## [1] 32
## [1] 64
The vector of times does NOT have to be a numeric vector; it can be any vector
value <- 2
times <- c('one', 'two', 'three', 'four')
for (i in times) {
value <- value * 2
print(value)
}
## [1] 4
## [1] 8
## [1] 16
## [1] 32
However, if the iterator is used inside the loop in a numerical computation, then the vector of times will almost always be a numeric vector:
set.seed(4321)
numbers <- rnorm(5)
for (h in 1:length(numbers)) {
if (numbers[h] < 0) {
value <- sqrt(-numbers[h])
} else {
value <- sqrt(numbers[h])
}
print(value)
}
## [1] 0.6532667
## [1] 0.4728761
## [1] 0.8471168
## [1] 0.9173035
## [1] 0.3582698
Sometimes we need to skip a loop iteration if a given condition is met, this can be done with a next statement
for (iterator in times) {
expr1
expr2
if (condition) {
next
}
expr3
expr4
}
Example:
x <- 2
for (i in 1:5) {
y <- x * i
if (y == 8) {
next
}
print(y)
}
## [1] 2
## [1] 4
## [1] 6
## [1] 10
It is common to have nested loops
for (iterator1 in times1) {
for (iterator2 in times2) {
expr1
expr2
...
}
}
Example: Nested loops
# some matrix
A <- matrix(1:12, nrow = 3, ncol = 4)
A
## [,1] [,2] [,3] [,4]
## [1,] 1 4 7 10
## [2,] 2 5 8 11
## [3,] 3 6 9 12
Example: Nested Loops
# reciprocal of values less than 6
for (i in 1:nrow(A)) {
for (j in 1:ncol(A)) {
if (A[i,j] < 6) A[i,j] <- 1 / A[i,j]
}
}
A
## [,1] [,2] [,3] [,4]
## [1,] 1.0000000 0.25 7 10
## [2,] 0.5000000 0.20 8 11
## [3,] 0.3333333 6.00 9 12
-
R loops have a bad reputation for being slow.
-
Experienced users will tell you: “tend to avoid
for
loops in R” (me included). -
It is not really that the loops are slow; the slowness has more to do with the way R handles the boxing and unboxing of data objects, which may be a bit inefficient.
-
R provides a family of functions that are usually more efficient than loops (i.e.
apply()
functions). -
For this course, especially if you have NO programming experience, you should ignore any advice about avoiding loops in R.
-
You should learn how to write loops, and understand how they work; every programming language provides some type of loop structure.
-
In practice, many (programming) problems can be tackled using some loop structure.
-
When using R, you may need to start solving a problem using a loop. Once you solved it, try to see if you can find a vectorized alternative.
-
It takes practice and experience to find alternative solutions to
for
loops. -
There are cases when using
for
loops is not that bad.
repeat
executes the same code over and over until a stop condition is
met:
repeat {
# keep
# doing
# something
if (stop_condition) {
break
}
}
The break
statement stops the loops. If you enter an infinite loop,
you can manually break it by pressing the ESC
key.
value <- 2
repeat {
value <- value * 2
print(value)
if (value >= 40) {
break
}
}
## [1] 4
## [1] 8
## [1] 16
## [1] 32
## [1] 64
To skip a current iteration, use next
value <- 2
repeat {
value <- value * 2
print(value)
if (value == 16) {
value <- value * 2
next
}
if (value > 80) break
}
## [1] 4
## [1] 8
## [1] 16
## [1] 64
## [1] 128
It can also be useful to repeat a computation until a condition is
false. A while
loop provides this form of control flow.
while (condition) {
# keep
# doing
# something
# until
# condition is FALSE
}
while
loops are backwardrepeat
loopswhile
checks first and then attempts to execute- computations are carried out for as long as the condition is true
- the loop stops when the condition is FALSE
- If you enter an infinite loop, break it by pressing
ESC
key
value <- 2
while (value < 40) {
value <- value * 2
print(value)
}
## [1] 4
## [1] 8
## [1] 16
## [1] 32
## [1] 64
Let’s see one last example of a for
loop, and how to achieve the same
task with while
and repeat
loops.
Say you have a vector x <- c(2, 4, 6, 8, 10)
, and the goal is to
obtain the sum of the elements in x
; in other words get sum(x)
but
using loops.
# using a for loop
x <- c(2, 4, 6, 8, 10)
# initialize output
sumx <- 0
for (i in seq_along(x)) {
print(paste('iteration:'), i)
sumx <- sumx + x[i]
print(paste('sum =', sumx))
}
## [1] "iteration:"
## [1] "sum = 2"
## [1] "iteration:"
## [1] "sum = 6"
## [1] "iteration:"
## [1] "sum = 12"
## [1] "iteration:"
## [1] "sum = 20"
## [1] "iteration:"
## [1] "sum = 30"
sumx
## [1] 30
Now let’s do it with a while loop
# initialize output
sumx <- 0
# initialize counter
i <- 1
# while loop
while (i <= length(x)) {
print(paste('iteration:', i))
sumx <- sumx + x[i]
print(paste('sum =', sumx))
i <- i + 1
}
## [1] "iteration: 1"
## [1] "sum = 2"
## [1] "iteration: 2"
## [1] "sum = 6"
## [1] "iteration: 3"
## [1] "sum = 12"
## [1] "iteration: 4"
## [1] "sum = 20"
## [1] "iteration: 5"
## [1] "sum = 30"
sumx
## [1] 30
And finally with a repeat
loop:
# initialize output
sumx <- 0
# initialize counter
i <- 1
# repeat loop (visualizing iterations)
repeat {
print(paste('iteration:', i))
sumx <- sumx + x[i]
print(paste('sum =', sumx))
i <- i + 1
if (i > length(x)) {
break
}
}
## [1] "iteration: 1"
## [1] "sum = 2"
## [1] "iteration: 2"
## [1] "sum = 6"
## [1] "iteration: 3"
## [1] "sum = 12"
## [1] "iteration: 4"
## [1] "sum = 20"
## [1] "iteration: 5"
## [1] "sum = 30"
sumx
## [1] 30
- If you don’t know the number of times something will be done, you
can use either
repeat
orwhile
while
evaluates the condition at the beginningrepeat
executes operations until a stop condition is met- If you know the number of times that something will be done, use
for
for
needs an iterator and a vector of times
- What happens if you pass
NA
as a condition toif()
? - What happens if you pass
NA
as a condition toifelse()
? - What types of values can be passed as the first argument to
switch()
? - How do you stop a
repeat
loop executing? - How do you jump to next iteration of a loop?