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.

my_numbers <- c(1,2,5,6,8,12, 14.5)

# only integers are allowed (i.e., no decimals)

my_numbers <- as.integer(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

one_number <- my_numbers[4]
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

one_number <- my_numbers[3]
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.

my_numbers <- c(1,2,5,6,8,12, 14.5)

# only integers are allowed (i.e., no decimals)

my_numbers <- as.integer(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

one_number <- my_numbers[4]
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

one_number <- my_numbers[3]
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

my_class_df <- 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

#  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 

Jenny_score <- as.numeric(subset(my_class_df, students == "Jenny", select = "exam1_scores"))
Jenny_score
#[1] 87.5

## We can process the Jenny's score to letter grades using if, if else and else 

Jenny_letter_grade <- character()

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

my_grader_function <- function(test_file_path,
                               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 <- test_file_path
is_excel <- is_it_an_excel
name_students <- name_of_column_with_students
name_exams <- name_of_column_with_exams
max_score_vector <- max_score_per_exam
write_out <- write_output_file

# read file

if(is_excel) {

tests_df <- read.xlsx(xlsxFile = test_file,
                                   sheet = 1,
                                startRow = 1,
                                colNames = TRUE)
             } else {
tests_df <- read.table (file = test_file,
                                    header = TRUE, 
                                       sep = "\t",
                          stringsAsFactors = FALSE)
             }

max_score <- sum(max_score_vector)
tests_df$final_score <- (rowSums(tests_df[2:ncol(tests_df)])/max_score)*100
cat("\n--- you imported this information and final score calculated:\n")
print(tests_df)

# calculate total and grade for each student

all_final_scores <- tests_df$final_score

all_student_letter_grade <- character()

for(i in 1:nrow(tests_df)) {
         # i <- 1
         one_student_score <- all_final_scores[i]
         

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"}

all_student_letter_grade[i] <- one_student_letter_grade 

                             }

tests_df$final_letter_grade <- all_student_letter_grade

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

results <- my_grader_function(test_file_path = "~/Desktop/Teach_R/my_working_directory/test_example.xlsx",
                   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

my_class_df <- 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

#  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

Jenny_score <- as.numeric(subset(my_class_df, students == "Jenny", select = "exam1_scores"))
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)

did_Jenny_pass <- ifelse (Jenny_score >=75, "Jenny PASSED her exam", "Jenny FAILED her exam")
print(did_Jenny_pass)
#[1] "Jenny PASSED her exam"

## We can do also a chain of contionals to assign a letter grade using ifelse 

Jenny_letter_grade <- ifelse(Jenny_score >= 92.0, "A",
                      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

my_number <- 2

# 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

my_class_df <- 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
#  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

students_score <- my_class_df$exam1_scores
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

students_letter_grade <- character()

for (i in 1:length(students_score)) {

# we iterate and calculate the letter_grade one student at a time

one_students_score <- students_score[i]

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"}

                                     }
                                     rm <- i # we remove the i index

## 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

my_class_df$letter_grade <- students_letter_grade
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

my_numbers <- c(1,3,45,33,5,9,7,11,14,15,19,23,22,31,30)

# notice all the {} they should close in the following loop, otherwise the loop cannot run

sampled_number <- 1

while(!sampled_number == 7) {
                 sampled_number <- sample(my_numbers, size = 1) # it sample randomly one 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

x <- 7
y <- 0

repeat {

       y <- y + 1
       cat("this is the repetition number ** ", y, " **\n")
       cat("the result of the function is:", x,"\n")
             x <- x * 2

       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
                                      }
                  square_of_my_value <- my_value^2
                      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
my_stop_the_loop_value <- 5
my_initial_value <- 10
my_value_to_skip <-7

## while loop with a if test
while(my_initial_value > my_stop_the_loop_value) {
     
     my_initial_value <- my_initial_value - 1
      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 
                                              } 

         report_value <- my_initial_value^2
     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
my_stop_the_loop_value <- 10
my_initial_value <- 5
my_value_to_skip <- 7

## 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 <- my_initial_value + 1
                                             next 
                                              } 

         my_initial_value <- my_initial_value + 1
     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
my_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
#$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_data <- mtcars

## PLACE HOLDER
mtcars_names_vector <- rownames(mtcars_data)

28.14 Other loop functions:mapply

PLACE HOLDER

## PLACE HOLDER
mtcars_data <- mtcars

## PLACE HOLDER
mtcars_names_vector <- rownames(mtcars_data)

28.15 Other loop functions:tapply

PLACE HOLDER

## PLACE HOLDER
mtcars_data <- mtcars

## PLACE HOLDER
mtcars_names_vector <- rownames(mtcars_data)

28.16 Other loop functions:split

PLACE HOLDER

## PLACE HOLDER
mtcars_data <- mtcars

## PLACE HOLDER
mtcars_names_vector <- rownames(mtcars_data)