people <- c("Dorothy", "Tin Man", "Scarecrow", "Lion")
for ( person in people ) {
cat("Hello, ", person, "!\n", sep = "")
}
Hello, Dorothy!
Hello, Tin Man!
Hello, Scarecrow!
Hello, Lion!
(Section 4.3)
for
-LoopsFlow-control in R (and in many computer languages) comes in three forms:
readline()
)if
and if ... else
)for
-loopswhile
-loopsfor
-LoopThe reserved word for
is used to make R perform execute a body of code on each of the elements of a specified vector. Here is a simple example:
people <- c("Dorothy", "Tin Man", "Scarecrow", "Lion")
for ( person in people ) {
cat("Hello, ", person, "!\n", sep = "")
}
Hello, Dorothy!
Hello, Tin Man!
Hello, Scarecrow!
Hello, Lion!
Note that the index variable person
has a name that describes its value.
The general form of a loop is:
index
is the index variable. It becomes each element of the vector iterable
.iterable
can be any vector. It’s elements will be traversed, one by one.index
becomes each element of the vector iterable
in turn.index
, the code in the brackets is executed.To iterate is to do a thing again and again.
Index Variable
The variable in a for
loop that takes on each of the values of the iterable in succession.
Iterable
The vector that provides the sequence of values for the index variable in a for
loop.
i
does not appear in the body of the loop;Suppose we have information in two vectors:
And we want to say:
Hello, Dorothy, you desire Kansas!
Hello, Tin Man, you desire brains!
Hello, Scarecrow, you desire a heart!
Hello, Lion, you desire courage!
How to do it?
We can iterate through the indices of of the vectors:
Hello, Dorothy, you desire Kansas!
Hello, Tin Man, you desire brains!
Hello, Scarecrow, you desire a heart!
Hello, Lion, you desire courage!
(Note: Single letters (i
, j
, etc.) are often used as names for index-variables in indirect iteration.)
Use length()
to make R figure out when to stop the loop:
Write a for
-loop that produces the following in the Console:
The square of 1 is 1.
The square of 2 is 4.
The square of 3 is 9.
The square of 4 is 16.
The square of 5 is 25.
Hint:
Let’s store the squares of the first ten whole numbers.
Quick way:
But let’s also do it with a for
-loop.
First, create a numeric vector of length 10, currently empty:
Now iterate through a loop:
for (i in 1:length(squares) ) {
squares[i] <- i^2 # put i-th square in i-th place of squares
}
squares
[1] 1 4 9 16 25 36 49 64 81 100
This is slower than vectorization, but sometimes is the only way to store results.
Run this:
This code simulates flipping a fair coin 10 times:
[1] "Tails" "Heads" "Heads" "Tails" "Tails" "Heads" "Tails" "Tails" "Tails"
[10] "Heads"
Accomplish the same thing with a for
-loop that stores results.
If you don’t learn anything else in this Chapter, at least learn this!!
break
-ing Out of a LoopWe can quickly search a vector to see if it contains a value:
Let’s write a “talky” function to perform the search.
Checked index 1 in the vector. No match there ...
Found Tin Man at index 2.
Checked index 3 in the vector. No match there ...
Checked index 4 in the vector. No match there ...
It seems silly to go on after we found a match!
break
The reserved word break
gets you out of a loop.
Execution continues after the closing bracket of the loop.
break
PatchverboseSearch <- function(elem, vec) {
found <- FALSE
for ( i in 1: length(vec) ) {
if ( vec[i] == elem ) {
found <- TRUE
cat("Found ", elem, " at index ", i, ".\n", sep = "")
break
} else {
cat(
"Checked index ", i,
" in the vector. No match there ...\n",
sep = "")
}
}
if ( found ) {
cat("Success!")
} else {
cat("No match: sad!")
}
}
Checked index 1 in the vector. No match there ...
Found Tin Man at index 2.
Success!
Checked index 1 in the vector. No match there ...
Checked index 2 in the vector. No match there ...
Checked index 3 in the vector. No match there ...
Checked index 4 in the vector. No match there ...
No match: sad!
while
-LoopsScarecrow is walking through a meadow that contains flowers of several colors:
He picks until he gets two blue flowers. We would like reports of his activities.
A vector for the :
The default value for length
is 0, so this is an empty character vector:
We will add to it.
sample()
is Random, So …… if you try it, your results will likely be different!
scarecrow_walk <- function(flower_colors, blues_desired) {
reports <- character()
count <- 0
i <- 1
while (count < blues_desired) {
flower <- sample(flower_colors, size = 1)
outcome <- paste(
"On pick ", i, ", Scarecrow got a ",
flower, " flower.", sep = ""
)
reports[i] <- outcome
i <- i + 1
if (flower == "blue") count <- count + 1
}
reports
}
Let’s try it:
How many flowers did Scarecrow pick? This many:
Suppose we ran the function like this:
We have to avoid infinite loops!
scarecrow_walk <- function(flower_colors, blues_desired) {
## stop if no blue flowers in meadow:
if (!("blue" %in% flower_colors)) {
return(cat("Your field needs blue flowers."))
}
## if we get here, it is safe to proceed:
reports <- character()
count <- 0
i <- 1
while (count < blues_desired) {
flower <- sample(flower_colors, size = 1)
outcome <- paste(
"On pick ", i, ", Scarecrow got a ",
flower, " flower.", sep = ""
)
reports[i] <- outcome
i <- i + 1
if (flower == "blue") count <- count + 1
}
reports
}
First version, with if
:
Second Version, with if ... else
:
Better to let the user guess until correct.
Use a while
-loop for this.
n <- 20
number <- sample(1:n, size = 1)
cat("I'm thinking of a whole number from 1 to ", n, ".\n", sep = "")
guessing <- TRUE
while (guessing) {
guess <- readline("What's your guess? (Enter q to quit.) ")
if ( guess == "q" ) {
cat("Bye!\n")
break
} else if ( as.numeric(guess) == number ) {
guessing <- FALSE
cat("You are correct! Thanks for playing!")
}
}
guess_my_number <- function(n) {
number <- sample(1:n, size = 1)
cat("I'm thinking of a whole number from 1 to ", n, ".\n", sep = "")
guessing <- TRUE
while (guessing) {
guess <- readline("What's your guess? (Enter q to quit.) ")
if ( guess == "q" ) {
cat("Bye!\n")
break
} else if ( as.numeric(guess) == number ) {
guessing <- FALSE
cat("You are correct! Thanks for playing!")
}
}
}
Give the user some feedback when the guess is incorrect:
guess_my_number_improved <- function(n) {
number <- sample(1:n, size = 1)
cat("I'm thinking of a whole number from 1 to ", n, ".\n", sep = "")
guessing <- TRUE
while (guessing) {
guess <- readline("What's your guess? (Enter q to quit.) ")
guessing <- TRUE
if (guess == "q") {
cat("Bye!\n")
break
} else if (as.numeric(guess) == number) {
guessing <- FALSE
cat("You are correct! Thanks for playing!")
} else {
# If we get to this point the guess was not correct.
# Issue hint:
hint <- ifelse(as.numeric(guess) > number, "high", "low")
cat("Your guess was ", hint, ". Keep at it!\n", sep = "")
}
# if still guessing, we will repeat the loop
}
}
What do you think will happen? (Do not run this.)
Increment the counter:
while
-loop Summarywhile
constructs a loop that runs as long as a specified condition is true.