Let’s talk about for loops
.
Sometimes, you want to cycle through your data and do stuff do it, one-at-a-time. R has a lot of methods for doing so.
One method is using the apply
family of functions, and
this is generally seen to be a preferred method for many
applications.
However, the point of this session is to teach a
for loop
, so we will not use those (but maybe sometime in
the future?)
The basic logic of a for loop is:
1. for
every something in some range
2. do something until that range is exhausted
for loop
The way to write a for loop is similar to the if
and
else
statements we used earlier in the session on function
building, including our friends the brackets. The basic syntax is:
for(elements in range){
do something
}
For example, we could ask R to print out each element of a vector. We
will use i
to represent the items that are being looped
through. We could use any arbitrary value because it represents a
variable that will stand for each element inside of a loop.
# define a vector
v1 = c('v', 'u', 'w')
for(i in v1){
print(i)
}
## [1] "v"
## [1] "u"
## [1] "w"
Can you write a for loop
that prints out the numbers
0-10 in reverse order?
for(i in seq(10, 1, -1)) {
print(i)
}
## [1] 10
## [1] 9
## [1] 8
## [1] 7
## [1] 6
## [1] 5
## [1] 4
## [1] 3
## [1] 2
## [1] 1
We can do more than printing within a for loop
. For
example, this loop performs a mathematical operation on each item:
for(i in seq(10000, 1000, -1000)){
i <- -1000/i
print(i)
}
## [1] -0.1
## [1] -0.1111111
## [1] -0.125
## [1] -0.1428571
## [1] -0.1666667
## [1] -0.2
## [1] -0.25
## [1] -0.3333333
## [1] -0.5
## [1] -1
Can you write a for loop
which doubles the values
between 1 and 10?
for(number in 1:10){
number = number*2
print(number)
}
## [1] 2
## [1] 4
## [1] 6
## [1] 8
## [1] 10
## [1] 12
## [1] 14
## [1] 16
## [1] 18
## [1] 20
You should now understand the basics of performing an explicitly
defined for loop
. Let’s add a layer of complexity and add a
conditional statement inside of our for loop
using an
if
and else
statement. You do this exactly the
same way that we learned inside of user-defined functions. For example,
this loop prints every number greater than 2 from a vector of
numbers:
for(i in c(1,2.5,1.2, 2.3, 5)){
if(i > 2){
print(i)
}
}
## [1] 2.5
## [1] 2.3
## [1] 5
You can then add an else statement to do something when the first
if
does not trigger:
for(i in c(1,2.5,1.2, 2.3, 5, 2)){
if(i > 2){
print(i)
} else {
message(i, ' is not larger than 2!')
}
}
## 1 is not larger than 2!
## [1] 2.5
## 1.2 is not larger than 2!
## [1] 2.3
## [1] 5
## 2 is not larger than 2!
Create a variable named countries
which contains the
strings `New Zealand’, ‘Australia’, and the three countries which are
part of North America. Type out the full name of each country - do not
use acronyms.
Then write a for loop
which checks whether the name of
the country is longer than 6 letters. If it is, print the name of the
country and a short message
about that country. If the
length is less than 6, print the name of the country and the phrase ‘I
guess your name is only six letters long.’
You will have to use length(unlist(strsplit(word, '')))
in order to turn each word into letters and check the length.
countries <- c('New Zealand', 'Australia', 'United States of America', 'Canada', 'Mexico')
country_output <- function(){
for(c in countries){
if(length(unlist(strsplit(c, ''))) > 6){
message('The country ', c, ' seems to have a long name!' )
} else {
print(paste(c, "I guess your name is only six letters long or less."))
}
}
}
Your output should look something like this:
country_output()
## The country New Zealand seems to have a long name!
## The country Australia seems to have a long name!
## The country United States of America seems to have a long name!
## [1] "Canada I guess your name is only six letters long or less."
## [1] "Mexico I guess your name is only six letters long or less."
We can make loops even more intelligent by storing information in a loop as it processes. This information can be checked against future loops and decisions can be made along the way. Importantly, any temporary variable stored within a loop will be reset each time the loop starts. For example, compare these two loops:
# x is set to zero at the start of each loop
for(i in 1:10){
x = 0
x = x + 1
print(x)
}
## [1] 1
## [1] 1
## [1] 1
## [1] 1
## [1] 1
## [1] 1
## [1] 1
## [1] 1
## [1] 1
## [1] 1
Now look what happens when we set to 0 outside of the for loop
# x is defined outside of the for loop
x <- 0
for(i in 1:10){
x = x + 1
print(x)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
## [1] 6
## [1] 7
## [1] 8
## [1] 9
## [1] 10
As such it’s pretty important to properly scope your variables for a loop - otherwise you might accidentally reset or not reset an important variable each time, which could have negative consequences if you are checking the variable for a reason .
Compare these two for loops - which one is better?
# temp variable stored outside a loop
winner = 0
for(i in c(1,4,6,3,8,2,2,4,100)){
if(i > 3 & i > winner){
winner = i
}
message('the current winner is ', winner)
}
## the current winner is 0
## the current winner is 4
## the current winner is 6
## the current winner is 6
## the current winner is 8
## the current winner is 8
## the current winner is 8
## the current winner is 8
## the current winner is 100
# temp variable stored inside a loop
for(i in c(1,4,6,3,8,2,2,4,100)){
winner = 0
if(i > 3 & i > winner){
winner = i
}
message('the current winner is ', winner)
}
## the current winner is 0
## the current winner is 4
## the current winner is 6
## the current winner is 0
## the current winner is 8
## the current winner is 0
## the current winner is 0
## the current winner is 4
## the current winner is 100
At this point we want to start storing our for loops inside functions so we can control the scope of variables used for any particular loop. If we only keep a variable inside a function, it will not enter our global environment (and thus not cause later issues. )
loopy <- function(){
# this temporary variable is inside a function but not inside the for loop.
output = ''
for(i in unlist(strsplit('Hello World', ''))){
output <- i
print(output)
}
}
# run the function
loopy()
## [1] "H"
## [1] "e"
## [1] "l"
## [1] "l"
## [1] "o"
## [1] " "
## [1] "W"
## [1] "o"
## [1] "r"
## [1] "l"
## [1] "d"
What happens when I try to call output
from outside of
the function?
# output
# Error: object 'output' not found
Create a function named long_name_checker
which takes a
single argument names
.
Inside the function, check whether each name in a list is longer than 5 letters. If so, it’s a long name. If it’s longer than 8 letters, it’s a super long name. Otherwise it’s a short name. Create some appropriate output messages for each condition.
Test it with these names:
names = c('', 'Jerry', 'Elaine', 'Kramer', 'George', 'Seinfeld', 'Fraser', 'Rumplestiltskin')
long_name_checker <- function(list_of_names){
for(i in list_of_names){
name_length = length(unlist(strsplit(i, '')))
if(name_length >= 8){
message(i, 'is a super long name!')
} else if(name_length > 5 & name_length < 8){
message(i, ' your name is long')
} else {
message()
}
}
}
names = c('Jerry', 'Elaine', 'Kramer', 'George', 'Seinfeld', 'Fraser', 'Rumplestiltskin')
long_name_checker(names)
##
## Elaine your name is long
## Kramer your name is long
## George your name is long
## Seinfeldis a super long name!
## Fraser your name is long
## Rumplestiltskinis a super long name!
Make a new function named long_name_checker_02
which is
a modified version of your function from Task 04 so that it now stores
all names that count as super long (which should be two names). At the
end of your first for loop, add another for loop which
then tells you which of the super long names are the longest. Use a
message to output the correct results.
Store the names in an empty variable named
super_long_names
- you can initialize it with
super_long_names <- c()
. You must store this variable
inside the function - so think carefully about where
you place it. You will also need to store a temporary variable to check
which of the super long names is the longest - think carefully where
this one goes too!
long_name_checker_02 <- function(list_of_names){
super_long_names = c()
for(i in list_of_names){
name_length = length(unlist(strsplit(i, '')))
if(name_length >= 8){
message(i, ' is a super long name!')
super_long_names <- c(super_long_names, i)
} else if(name_length > 5 & name_length < 8){
message(i, ' your name is long')
} else {
message(i, ' i guess you have a short name. ')
}
}
for(s in super_long_names){
longest_name = ''
super_long_length = length(unlist(strsplit(s, '')))
if(super_long_length > length(unlist(strsplit(longest_name, '')))){
longest_name = s
}
}
message(longest_name, ' CONGRATULATIONS, you have the longest name.')
}
names = c('Jerry', 'Elaine', 'Kramer', 'George', 'Seinfeld', 'Fraser', 'Rumplestiltskin')
long_name_checker_02(names)
## Jerry i guess you have a short name.
## Elaine your name is long
## Kramer your name is long
## George your name is long
## Seinfeld is a super long name!
## Fraser your name is long
## Rumplestiltskin is a super long name!
## Rumplestiltskin CONGRATULATIONS, you have the longest name.
Define a function named print_letters
that takes no
arguments.
This function will contain a for loop which checks each letter of the alphabet. If the letter is a vowel, the loop should print the vowel and the order of the vowel in the alphabet (e.g., ‘A’ is the first vowel, ‘E’ is the second vowel - so your output for vowels should range from 1-5 - don’t include ‘Y’). If the letter is a consonant, print the numerical position of that letter in the alphabet (e.g., ‘B’ is 2, ‘Z’ = 26.)
Tips:
if
and an else
statementprint_letters <- function(){
counter.all <- 0
counter.vowel <- 0
for(l in letters){
if(l %in% c('a','e','i', 'o', 'u')){
counter.vowel = counter.vowel + 1
counter.all = counter.all + 1
print(paste(l, counter.vowel))
} else {
counter.all = counter.all +1
print(paste(l, counter.all))
}
}
}
Successful output looks like this:
print_letters()
## [1] "a 1"
## [1] "b 2"
## [1] "c 3"
## [1] "d 4"
## [1] "e 2"
## [1] "f 6"
## [1] "g 7"
## [1] "h 8"
## [1] "i 3"
## [1] "j 10"
## [1] "k 11"
## [1] "l 12"
## [1] "m 13"
## [1] "n 14"
## [1] "o 4"
## [1] "p 16"
## [1] "q 17"
## [1] "r 18"
## [1] "s 19"
## [1] "t 20"
## [1] "u 5"
## [1] "v 22"
## [1] "w 23"
## [1] "x 24"
## [1] "y 25"
## [1] "z 26"