Session 28 – Control Structures & Loops in R
28.1 Controling the flow
In most cases when you run an R program or script, you want to control how the flow of data and the product of intermediate processes that include how the data or part/by-products of the data are stored, tested, transformed or discarded. These control structures serve as commands for the machine to take automated descisions on the data as it moves from one process to another. For example, as the program runs, the data are processed following a linear sequence of instructions but in some steps these instructions might bifurcate into alternative analyses based on a condition on the data (e.g., if test on the data is true do A else do B). Likewise, sometimes the data has a structure that includes a collection of similar elements that could be repeatedly processed with the same set of instructions for certain number of times or while a condition is fulfilled (e.g., repeat process on data or parts of the data during a set number of times).
In R, basic control structures include conditional functions which are used to execute one or more statements if a condition is met by the data or part of the data and loops which are iteration or repeations of a statement or process during a certain number of times or while a condition is fulfilled.
28.2 Conditional if
These conditional statements allow to control the flow of code based on a binary or Boolean expression: an expression that evaluates to either true or false. It is the most simple form and only a test if is necessary to determine if the condition is TRUE, which allows the statement contained such as in curly brackets { } to get executed. However, if the condition is FALSE then no statement is excecuted.
For example, we can test if a value(s) in vector is(are) even by assigning a test
## Test if a number is even: A number is even if division by 2 give a remainder of 0; otherwise, if remainder is 1, the number is odd.
<- c(1,2,5,6,8,12, 14.5)
my_numbers
# only integers are allowed (i.e., no decimals)
<- as.integer(my_numbers)
my_numbers
my_numbers#[1] 1 2 5 6 8 12 14
# choose a single number, in this case the 4th element that is 6, an even number
<- my_numbers[4]
one_number
one_number
#[1] 6
# if conditional test
if((one_number%% 2) == 0) {
print(paste(one_number,"is even"))
}
#[1] "6 is even"
## Let's try with an odd number
<- my_numbers[3]
one_number
one_number
#[1] 5
# if conditional test
if((one_number%% 2) == 0) {
print(paste(one_number,"is even"))
}
# There is not output, as the condition is not met by our choosen number: 5
28.3 Conditional if
and else
An extension of the if conditional is that if after the computer determine if the condition is TRUE, which allows the statement contained such as in curly brackets { } to get executed. However, if the condition is FALSE then an alternative statement is excuted preceded by else contained such as in curly brackets { } to get executed.
We can use the previous example to illustrate:
## Test if a number is even: A number is even if division by 2 give a remainder of 0; otherwise, if remainder is 1, the number is odd.
<- c(1,2,5,6,8,12, 14.5)
my_numbers
# only integers are allowed (i.e., no decimals)
<- as.integer(my_numbers)
my_numbers
my_numbers#[1] 1 2 5 6 8 12 14
# choose a single number, in this case the 4th element that is 6, an even number
<- my_numbers[4]
one_number
one_number
#[1] 6
# if conditional test
if((one_number%% 2) == 0) {
print(paste(one_number,"is even"))
else {
} print(paste(one_number,"is odd"))
}
#[1] "6 is even"
## Let's try with an odd number
<- my_numbers[3]
one_number
one_number
#[1] 5
# if conditional test
if((one_number%% 2) == 0) {
print(paste(one_number,"is even"))
else {
} print(paste(one_number,"is odd"))
}
#[1] "5 is odd"
28.4 Nested conditionals if
, else
, and if else
We can create nested conditionals where you can have more than 2 conditions. In this case, we can try a chain of conditional tests separated
by if else (test) { statements to run}
and it ends with else { statements to run}
if all (test) return FALSE.
For example, we want to test a series of 11 test (options) like for example assigning grade scores to their corresponding letter grade (A, A-, B+, B, B-, C+, C, C-, D+, D, and F). We can follow some consideration or test on how to assign numeric scores to letter grades (e.g., if the numeric score is more or eauql to 92, we should assign an A). Some of you might encounter this if you are TA and you have to give a letter grade based on the numeric scores of your students in an exam.
## We have a five students and you want to give them a letter grade based on their numeric scores
<- data.frame(students = c("Joe", "Moe", "Luke", "Clarisa", "Jenny"), exam1_scores = c(84.9,72.5,59.3,94.6,87.5))
my_class_df
my_class_df
# students exam1_scores
#1 Joe 84.9
#2 Moe 72.5
#3 Luke 59.3
#4 Clarisa 94.6
#5 Jenny 87.5
str(my_class_df)
#'data.frame': 5 obs. of 2 variables:
# $ students : chr "Joe" "Moe" "Luke" "Clarisa" ...
# $ exam1_scores: num 84.9 72.5 59.3 94.6 87.5
## We need to extract Jenny's score
<- as.numeric(subset(my_class_df, students == "Jenny", select = "exam1_scores"))
Jenny_score
Jenny_score#[1] 87.5
## We can process the Jenny's score to letter grades using if, if else and else
<- character()
Jenny_letter_grade
if(Jenny_score >= 92.0) { Jenny_letter_grade <- "A"
else if (Jenny_score >= 89.5 & Jenny_score < 92.0) {Jenny_letter_grade <- "A-"
} else if (Jenny_score >= 84.5 & Jenny_score < 89.5) {Jenny_letter_grade <- "B+"
} else if (Jenny_score >= 82.0 & Jenny_score < 84.5) {Jenny_letter_grade <- "B"
} else if (Jenny_score >= 79.5 & Jenny_score < 82.0) {Jenny_letter_grade <- "B-"
} else if (Jenny_score >= 74.5 & Jenny_score < 79.5) {Jenny_letter_grade <- "C+"
} else if (Jenny_score >= 72.0 & Jenny_score < 74.5) {Jenny_letter_grade <- "C"
} else if (Jenny_score >= 69.5 & Jenny_score < 72.0) {Jenny_letter_grade <- "C-"
} else if (Jenny_score >= 64.5 & Jenny_score < 69.5) {Jenny_letter_grade <- "D+"
} else if (Jenny_score >= 59.5 & Jenny_score < 64.5) {Jenny_letter_grade <- "D"
} else {Jenny_letter_grade <- "F"}
}
Jenny_letter_grade #[1] "B+"
cat("\n--- Jenny's score was :", Jenny_score, " this values corresponds to this letter grade: ", Jenny_letter_grade, "\n")
#--- Jenny's score was : 87.5 this values corresponds to this letter grade: B+
You can repeat the above process now with any student score if you want. Later, I will show you how to run this in a loop and get the letter grades of all your students at once.
We can make use of this type of control function within a function()
were we want to provide a list of grades with names and we want to output a final letter grade.
## This requires that you have openxlsx installed
install.packages("openxlsx")
## grader function
<- function(test_file_path,
my_grader_function is_it_an_excel = TRUE,
name_of_column_with_students = "student",
name_of_column_with_exams = c("exam_1", "exam_2","exam_3"),
max_score_per_exam = c(100,100,100),
write_output_file = TRUE){
# require
require(openxlsx)
# my input
<- test_file_path
test_file <- is_it_an_excel
is_excel <- name_of_column_with_students
name_students <- name_of_column_with_exams
name_exams <- max_score_per_exam
max_score_vector <- write_output_file
write_out
# read file
if(is_excel) {
<- read.xlsx(xlsxFile = test_file,
tests_df sheet = 1,
startRow = 1,
colNames = TRUE)
else {
} <- read.table (file = test_file,
tests_df header = TRUE,
sep = "\t",
stringsAsFactors = FALSE)
}
<- sum(max_score_vector)
max_score $final_score <- (rowSums(tests_df[2:ncol(tests_df)])/max_score)*100
tests_dfcat("\n--- you imported this information and final score calculated:\n")
print(tests_df)
# calculate total and grade for each student
<- tests_df$final_score
all_final_scores
<- character()
all_student_letter_grade
for(i in 1:nrow(tests_df)) {
# i <- 1
<- all_final_scores[i]
one_student_score
if(one_student_score >= 92.0) { one_student_letter_grade <- "A"
else if (one_student_score >= 89.5 & one_student_score < 92.0) {one_student_letter_grade <- "A-"
} else if (one_student_score >= 84.5 & one_student_score < 89.5) {one_student_letter_grade <- "B+"
} else if (one_student_score >= 82.0 & one_student_score < 84.5) {one_student_letter_grade <- "B"
} else if (one_student_score >= 79.5 & one_student_score < 82.0) {one_student_letter_grade <- "B-"
} else if (one_student_score >= 74.5 & one_student_score < 79.5) {one_student_letter_grade <- "C+"
} else if (one_student_score >= 72.0 & one_student_score < 74.5) {one_student_letter_grade <- "C"
} else if (one_student_score >= 69.5 & one_student_score < 72.0) {one_student_letter_grade <- "C-"
} else if (one_student_score >= 64.5 & one_student_score < 69.5) {one_student_letter_grade <- "D+"
} else if (one_student_score >= 59.5 & one_student_score < 64.5) {one_student_letter_grade <- "D"
} else {one_student_letter_grade <- "F"}
}
<- one_student_letter_grade
all_student_letter_grade[i]
}
$final_letter_grade <- all_student_letter_grade
tests_df
cat("\n--- you final letter grades:\n")
print(tests_df)
# write file
if(write_out) {write.table(tests_df, file = "my_students_letter_grade.txt", sep = "\t", row.names = FALSE)}
return(tests_df)
# end of function
}
## do not forget to set your working directory
setwd("~/Desktop/Teach_R/my_working_directory")
## run function
<- my_grader_function(test_file_path = "~/Desktop/Teach_R/my_working_directory/test_example.xlsx",
results is_it_an_excel = TRUE,
name_of_column_with_students = "student",
name_of_column_with_exams = c("exam_1", "exam_2","exam_3"),
max_score_per_exam = c(100,100,100),
write_output_file = FALSE)
#--- you imported this information and final score calculated:
# student exam_1 exam_2 exam_3 final_score
#1 Joe 45 80 90 71.66667
#2 Moe 60 70 75 68.33333
#3 Luke 78 75 79 77.33333
#4 Clasira 90 92 95 92.33333
#5 Jenny 67 70 70 69.00000
#6 Peter 80 82 90 84.00000
#7 Pablo 87 85 90 87.33333
#--- you final letter grades:
# student exam_1 exam_2 exam_3 final_score final_letter_grade
#1 Joe 45 80 90 71.66667 C-
#2 Moe 60 70 75 68.33333 D+
#3 Luke 78 75 79 77.33333 C+
#4 Clasira 90 92 95 92.33333 A
#5 Jenny 67 70 70 69.00000 D+
#6 Peter 80 82 90 84.00000 B
#7 Pablo 87 85 90 87.33333 B+
28.5 Conditional ifelse
You can abreviate the previous conditionals using ifelse
function for conditional element selection.
The ifelse
function returns a value after a test in the form of ifelse(test, yes, no) which is filled with elements selected from either yes or no depending on whether the element of test is TRUE or FALSE. This can be one test or a chain of nested tests.
## We have a five students and you want to give them a letter grade based on their numeric scores
<- data.frame(students = c("Joe", "Moe", "Luke", "Clarisa", "Jenny"), exam1_scores = c(84.9,72.5,59.3,94.6,87.5))
my_class_df
my_class_df
# students exam1_scores
#1 Joe 84.9
#2 Moe 72.5
#3 Luke 59.3
#4 Clarisa 94.6
#5 Jenny 87.5
str(my_class_df)
#'data.frame': 5 obs. of 2 variables:
# $ students : chr "Joe" "Moe" "Luke" "Clarisa" ...
# $ exam1_scores: num 84.9 72.5 59.3 94.6 87.5
## We need to extract Jenny's score
<- as.numeric(subset(my_class_df, students == "Jenny", select = "exam1_scores"))
Jenny_score
Jenny_score#[1] 87.5
## We can do a SIMPLE TEST to determine if Jenny's score is enough for PASS (if her score is >= 75) or FAIL (if it < 75)
<- ifelse (Jenny_score >=75, "Jenny PASSED her exam", "Jenny FAILED her exam")
did_Jenny_pass print(did_Jenny_pass)
#[1] "Jenny PASSED her exam"
## We can do also a chain of contionals to assign a letter grade using ifelse
<- ifelse(Jenny_score >= 92.0, "A",
Jenny_letter_grade ifelse(Jenny_score >= 89.5 & Jenny_score < 92.0, "A-",
ifelse(Jenny_score >= 84.5 & Jenny_score < 89.5, "B+",
ifelse(Jenny_score >= 82.0 & Jenny_score < 84.5, "B",
ifelse(Jenny_score >= 79.5 & Jenny_score < 82.0, "B-",
ifelse(Jenny_score >= 74.5 & Jenny_score < 79.5, "C+",
ifelse(Jenny_score >= 72.0 & Jenny_score < 74.5, "C",
ifelse(Jenny_score >= 69.5 & Jenny_score < 72.0, "C-",
ifelse(Jenny_score >= 64.5 & Jenny_score < 69.5, "D+",
ifelse(Jenny_score >= 59.5 & Jenny_score < 64.5, "D", "F"))))))))))
Jenny_letter_grade #[1] "B+"
cat("\n--- Jenny's score was :", Jenny_score, " this values corresponds to this letter grade: ", Jenny_letter_grade, "\n")
#--- Jenny's score was : 87.5 this values corresponds to this letter grade: B+
Notice that closing parenthesis might be tricky and only a good text editor will help you to identify if any is not closed
28.6 Loops that control iterations and repeations
We can use loops statements allow the control automation of processes that might require sequences of actions that are repeated until some condition is met or a counter reaches an specific number of repeats. The creative application of loops is one of the strengths of programming by giving the control of some repeatitive actions to few lines of code. In R (like other programming languages), there are general types that include:
28.7 The for
Loop
Those loops control the execution of a series of intructions usually contained within { }
.
In the for
loops, the statements are executed one after another in a consecutive order over a sequence of values in a counter or an index.
In this case, the number of iterations or repetitions is fixed in advance.
The counter or index changes every time whenever a new iteration starts (e.g., usually increases by one). For example:
## here is a short for loop for stament where a number is multiplied by itself during 5 iterations
<- 2
my_number
# the loop will iterate for 1 to 5 in the sequence 1:5
1:5
#[1] 1 2 3 4 5
for(i in 1:5) {
cat("-- this iteration is i = ",i)
<- my_number * my_number
my_number cat(" -- the result of the function in this loop is equal -- ", my_number, "\n")
if(i==5) {print("the for loop reached the end!!")}
}
#-- this iteration is i = 1 -- the result of the function in this loop is equal -- 4
#-- this iteration is i = 2 -- the result of the function in this loop is equal -- 16
#-- this iteration is i = 3 -- the result of the function in this loop is equal -- 256
#-- this iteration is i = 4 -- the result of the function in this loop is equal -- 65536
#-- this iteration is i = 5 -- the result of the function in this loop is equal -- 4294967296
#[1] "the for loop reached the end!!"
In this example, we can identify some of the components of the for
loop. An index named i
which is variable that will change by +1
in other words it starts as
i = 1
then in the next iteration is i = 2
until it reaches the limit 5 or i = 5
and stops the loop. Then we have the set of statements contained in { }
.
You can identify that the object my_number
is being replaced by the product of the multiplication *
such as my_number <- my_number * my_number
.
The cat()
function serves to report in the R console the results of the loop as it progresses between iterations. I also included a condition if(i==5){ }
where
the computer will report that at the end of the last iteration i==5
will report the for loop reached the end!!
.
We can retake the grading example and now we can add the letter grade to all students
## We have a five students and you want to give them a letter grade based on their numeric scores
<- data.frame(students = c("Joe", "Moe", "Luke", "Clarisa", "Jenny"), exam1_scores = c(84.9,72.5,59.3,94.6,87.5))
my_class_df
my_class_df# students exam1_scores
#1 Joe 84.9
#2 Moe 72.5
#3 Luke 59.3
#4 Clarisa 94.6
#5 Jenny 87.5
str(my_class_df)
#'data.frame': 5 obs. of 2 variables:
# $ students : chr "Joe" "Moe" "Luke" "Clarisa" ...
# $ exam1_scores: num 84.9 72.5 59.3 94.6 87.5
## we extract a vector with the scores
<- my_class_df$exam1_scores
students_score
students_score#[1] 84.9 72.5 59.3 94.6 87.5
## We need to get the letter grade for every student using a loop and stored in students_letter_grade character vector
<- character()
students_letter_grade
for (i in 1:length(students_score)) {
# we iterate and calculate the letter_grade one student at a time
<- students_score[i]
one_students_score
if(one_students_score >= 92.0) { students_letter_grade[i] <- "A"
else if (one_students_score >= 89.5 & one_students_score < 92.0) {students_letter_grade[i] <- "A-"
} else if (one_students_score >= 84.5 & one_students_score < 89.5) {students_letter_grade[i] <- "B+"
} else if (one_students_score >= 82.0 & one_students_score < 84.5) {students_letter_grade[i] <- "B"
} else if (one_students_score >= 79.5 & one_students_score < 82.0) {students_letter_grade[i] <- "B-"
} else if (one_students_score >= 74.5 & one_students_score < 79.5) {students_letter_grade[i] <- "C+"
} else if (one_students_score >= 72.0 & one_students_score < 74.5) {students_letter_grade[i] <- "C"
} else if (one_students_score >= 69.5 & one_students_score < 72.0) {students_letter_grade[i] <- "C-"
} else if (one_students_score >= 64.5 & one_students_score < 69.5) {students_letter_grade[i] <- "D+"
} else if (one_students_score >= 59.5 & one_students_score < 64.5) {students_letter_grade[i] <- "D"
} else {students_letter_grade[i] <- "F"}
}
}<- i # we remove the i index
rm
## These are the letter grades for each student
students_letter_grade#[1] "B+" "C" "F" "A" "B+"
## We can add these letter grades to our data frame, so we can see students names, numeric scores and letter grades
$letter_grade <- students_letter_grade
my_class_df
my_class_df# students exam1_scores letter_grade
#1 Joe 84.9 B+
#2 Moe 72.5 C
#3 Luke 59.3 F
#4 Clarisa 94.6 A
#5 Jenny 87.5 B+
28.8 The while
Loop
Those loops control the execution of a series of intructions usually contained within { }
. The number of repetitions is determined by a test and
the verification of its logical condition of an object resulting of an internal process within the { }
statements. This loop will keep repeating the process determined within { }
as long as the logical condition is TRUE,
if the longical condition changes to FALSE , then the while
loop will stop.
You should pay attention while using a while
loop, becasue this loop require the execution of some expression over and over again until the condition becomes FALSE.
If for some reason this condition never turns out to be FALSE, the while
loop will continue forever and you likely have to abort the program
(or the program will “crash”) and you will have to quit R or even restart your computer. So, please pay attention to the logical test associated with a while
loop and save anything before you
run such loops. Personally, I am not very fan of this loop as I find it very cumbersome to apply and control. I used it only under very specific conditions.
Here is a simple example of this loop.
## We will do a random sampling among 15 numbers, if the value sampled is 7 then the while stop
<- c(1,3,45,33,5,9,7,11,14,15,19,23,22,31,30)
my_numbers
# notice all the {} they should close in the following loop, otherwise the loop cannot run
<- 1
sampled_number
while(!sampled_number == 7) {
<- sample(my_numbers, size = 1) # it sample randomly one number
sampled_number
if(!sampled_number == 7) {
cat("the sampled number is -- ",sampled_number, " -- this is DIFFERENT than 7 and the while loop will CONTINUE\n")
else {
} cat("the sampled number is -- ",sampled_number, " -- this is EQUAL to 7 and the while loop will STOP\n")
}
}rm(sampled_number)
#the sampled number is -- 1 -- this is DIFFERENT than 7 and the while loop will CONTINUE
#the sampled number is -- 1 -- this is DIFFERENT than 7 and the while loop will CONTINUE
#the sampled number is -- 9 -- this is DIFFERENT than 7 and the while loop will CONTINUE
#the sampled number is -- 30 -- this is DIFFERENT than 7 and the while loop will CONTINUE
#the sampled number is -- 11 -- this is DIFFERENT than 7 and the while loop will CONTINUE
#the sampled number is -- 1 -- this is DIFFERENT than 7 and the while loop will CONTINUE
#the sampled number is -- 15 -- this is DIFFERENT than 7 and the while loop will CONTINUE
#the sampled number is -- 7 -- this is EQUAL to 7 and the while loop will STOP
In this example, it is included de symbol !
such as while(!sampled_number == 7)
. The symbol !
means negate or find the condition that is the oposite as
the stated test. In this case, I am telling the computer to keep sampling a number from the my_numbers
object and continue as long this number is not equal to 7.
28.9 The repeat
Loop
Those loops control the execution of a series of intructions usually contained within { }
.
Similar to while
loops, these are based on the verification of a logical condition. The condition is tested to be TRUE
at the start of each
iteration and while condition remain FALSE the process repeat
(i.e., loops).
The repeating process ends when the condition is verified to be TRUE as defined by the break
condition.
You have to be extra careful to avoid infinite loops, so the results of the instruction within the { }
must result at some point to be FALSE
so the break
condition can stop the repeat
part of the loop or otherwise you will end up with an infinite loop and you likely have to abort the program
(or the program will “crash”) and you will have to restart your computer.
Here is a simple example of this loop.
## We will repeat a proces by multipliying by 2 an starting number equal to 7 (x <- 7), if the value after a repetition is more than 24566 then the while stop
<- 7
x <- 0
y
repeat {
<- y + 1
y cat("this is the repetition number ** ", y, " **\n")
cat("the result of the function is:", x,"\n")
<- x * 2
x
if (x >= 24566){
cat("\n")
print ("we have reached a x value more or equal to 24566 and we will stop")
break
}
}
#7 this is the repetition number ** 1 **
#the result of the function is: 7
#this is the repetition number ** 2 **
#the result of the function is: 14
#this is the repetition number ** 3 **
#the result of the function is: 28
#this is the repetition number ** 4 **
#the result of the function is: 56
#this is the repetition number ** 5 **
#the result of the function is: 112
#this is the repetition number ** 6 **
#the result of the function is: 224
#this is the repetition number ** 7 **
#the result of the function is: 448
#this is the repetition number ** 8 **
#the result of the function is: 896
#this is the repetition number ** 9 **
#the result of the function is: 1792
#this is the repetition number ** 10 **
#the result of the function is: 3584
#this is the repetition number ** 11 **
#the result of the function is: 7168
#this is the repetition number ** 12 **
#the result of the function is: 14336
#[1] "we have reached a x value more or equal to 24566 and we will stop"
Again, I am not very fan of this loop as I find it very cumbersome to apply and control. I almost nerver use these repeat
loops.
28.10 The next
and break
statements
Controlling loops is essential when you are dealing with the evaluation or exceution of large datasets. One of those is to provide to the program the ability to skip the execution any remaining statements when some input data meet some conditions that make the execution of the following staments of the loop unachievable (e.g., the datum is missing or NA
) or it evaluation will take too long, cause the computer to “crash” or demand to much memory to be finished.
The next
control statement in the loop and allows skin a problematic datum and allows the execution of loop to continue. In other words, the next
control statement in combination with a test can allow to skip a given loop iteration without causing the loop termination.
The syntax of next statement is:
## like a if loops, if test is TRUE then next iteration in the loop
if (test_condition) {
next
}
The break
statement is similar to the next
statement, yet the break
does terminate the loop if a condition is met or a test is TRUE.
The syntax of break statement is:
## like a if loops, if test is TRUE then break the containing loop
if (test_expression) {
break
}
The next
and break
statements are mostly used inside a ‘for’, ‘while’ or ‘repeat’ loops to stop (i.e., using break
) or to skip an iterations (i.e., using next
)
while the loop is being executed.
Here is an example using a ‘for’ that interates from 1 to 10 as it increases by 1 (i.e., 1, 2, 3, 4, …, 10). That includes both the
next
and break
statements.
## an example of a for loop with the 'next' and 'break' arguments
for (my_value in 1:10) {
cat("my iteration correspond to my_value = ", my_value, "\n")
if (my_value == 6){
cat("--- NOTE: my_value is equal 6 and it will SKIP the square calculation for my_value of 6 and continue to 7 \n")
next
}
if (my_value == 9){
cat("--- NOTE: my_value is equal 9 and it will STOP the for loop and it will not print square calculation for my_value equal 9 and 10 \n")
break
}<- my_value^2
square_of_my_value cat("--- my_value square calculation is equal to ", square_of_my_value, "\n")
}
#my iteration correspond to my_value = 1
#--- my_value square calculation is equal to 1
#my iteration correspond to my_value = 2
#--- my_value square calculation is equal to 4
#my iteration correspond to my_value = 3
#--- my_value square calculation is equal to 9
#my iteration correspond to my_value = 4
#--- my_value square calculation is equal to 16
#my iteration correspond to my_value = 5
#--- my_value square calculation is equal to 25
#my iteration correspond to my_value = 6
#--- NOTE: my_value is equal 6 and it will SKIP the square calculation for my_value of 6 and continue to 7
#my iteration correspond to my_value = 7
#--- my_value square calculation is equal to 49
#my iteration correspond to my_value = 8
#--- my_value square calculation is equal to 64
#my iteration correspond to my_value = 9
#--- NOTE: my_value is equal 9 and it will STOP the for loop and it will not print square calculation for my_value equal 9 and 10
In this example, we used the next
statements after the program excecuted an if test ‘my_value == 6‘. If this test is TRUE (i.e., ‘my_value‘ is equal to 6) and it will cause to print the message ‘— NOTE: my_value is equal 6 and it will SKIP the square calculation for my_value of 6 and continue to 7‘ and skip to the next iteration. We also used the break
statements after the program excecuted an if test ‘my_value == 9‘. If this test is TRUE (i.e., ‘my_value‘ is equal to 9) and it will cause to print the message ‘— NOTE: my_value is equal 9 and it will STOP the for loop and it will not print square calculation for my_value equal 9 and 10‘ and break the loop and stop its progression. We can use next
and break
statements in ‘while’ or ‘repeat’ loops.
Here is a while
loop with an if
test, which if TRUE then next
to proceed to following iteration
## Initial values
<- 5
my_stop_the_loop_value <- 10
my_initial_value <-7
my_value_to_skip
## while loop with a if test
while(my_initial_value > my_stop_the_loop_value) {
<- my_initial_value - 1
my_initial_value cat("my current value is ", my_initial_value, "\n")
if (my_initial_value == my_value_to_skip) {
cat("NOTE: my current value is equal to my_value_to_skip:", my_value_to_skip,"\n")
cat("NOTE: my report value is WILL NOT BE PRINTED as it has been skipped \n")
next
}
<- my_initial_value^2
report_value cat("my report value is ",report_value, "\n")
}
#mmy current value is 9
#my report value is 81
#my current value is 8
#my report value is 64
#my current value is 7
#NOTE: my current value is equal to my_value_to_skip: 7
#NOTE: my report value is WILL NOT BE PRINTED as it has been skipped
#my current value is 6
#my report value is 36
#my current value is 5
#my report value is 25
Here is a repeat
loop with an if
test, which if TRUE then next
to proceed to following iteration. It also has a break
if reach a maximum iteration value.
## Initial values
<- 10
my_stop_the_loop_value <- 5
my_initial_value <- 7
my_value_to_skip
## repat loop with two if tests for break and next
repeat{
cat("my current value is ", my_initial_value, "\n")
if(my_initial_value == my_stop_the_loop_value) {
cat("NOTE: my current value is equal to my_stop_the_loop_value:", my_initial_value,"\n")
cat("NOTE: the repeat loop has stopped \n")
break
} if (my_initial_value == my_value_to_skip) {
cat("NOTE: my current value is equal to my_value_to_skip:", my_value_to_skip,"\n")
cat("NOTE: my report value is WILL NOT BE PRINTED as it has been skipped \n")
<- my_initial_value + 1
my_initial_value next
}
<- my_initial_value + 1
my_initial_value cat("my report value is ",my_initial_value, "\n")
}
#my current value is 5
#my report value is 6
#my current value is 6
#my report value is 7
#my current value is 7
#NOTE: my current value is equal to my_value_to_skip: 7
#NOTE: my report value is WILL NOT BE PRINTED as it has been skipped
#my current value is 8
#my report value is 9
#my current value is 9
#my report value is 10
#my current value is 10
#NOTE: my current value is equal to my_stop_the_loop_value: 10
#NOTE: the repeat loop has stopped
28.11 Other loop functions
There a list of loop functions that apply to vectors and lists. These require some trial an error until they perform your intended calculations.
28.12 lapply
functions
This function returns a list of the same length as vector or list, each element of which is the result of applying a function to the corresponding element of this vector or list. It will return a list object.
## an input list
<- list(numeric_vector = c(1, 3, 7, 10,5), my_df = data.frame(x = seq(1,10,2), y = c(34,23,45,78,101)))
my_list
my_list#$numeric_vector
#[1] 1 3 7 10 5
#
#$my_df
# x y
#1 1 34
#2 3 23
#3 5 45
#4 7 78
#5 9 101
## we want get the sum each element on this list
lapply(my_list,FUN=sum)
#$numeric_vector
#[1] 26
#
#$my_df
#[1] 306
## maximum
lapply(my_list,FUN=max)
#$numeric_vector
#[1] 10
#
#$my_df
#[1] 101
## we want get the mean each element on this list. However, notice that some functions cannot be applied to some elements (e.g., mean to a data.frame)
lapply(my_list,FUN=mean)
#$numeric_vector
#[1] 5.2
#
#$my_df
#[1] NA
#
#Warning message:
#In mean.default(X[[i]], ...) :
# argument is not numeric or logical: returning NA
28.13 Other loop functions:apply
PLACE HOLDER
## PLACE HOLDER
<- mtcars
mtcars_data
## PLACE HOLDER
<- rownames(mtcars_data) mtcars_names_vector
28.14 Other loop functions:mapply
PLACE HOLDER
## PLACE HOLDER
<- mtcars
mtcars_data
## PLACE HOLDER
<- rownames(mtcars_data) mtcars_names_vector
28.15 Other loop functions:tapply
PLACE HOLDER
## PLACE HOLDER
<- mtcars
mtcars_data
## PLACE HOLDER
<- rownames(mtcars_data) mtcars_names_vector
28.16 Other loop functions:split
PLACE HOLDER
## PLACE HOLDER
<- mtcars
mtcars_data
## PLACE HOLDER
<- rownames(mtcars_data) mtcars_names_vector