6  Control Structure

::: Chapter is still under construction :::

Control structures are components of programming that determines the order in which instructions are executed within a program. It allows us control the flow of execution of R expressions (Peng 2016). Control structure allows us to execute different expressions based on conditions.

Basically, they introduce some level of strictness and flexibility at the same time which is determined by the programmer. In addition to getting results based on conditions, they prevents unnecessary manual repetition of the same instruction through loops. Some of the control structure functions in R are:

While we won’t cover the whole list provided here, we will cover enough to help you in your research workflow. For example, case_when is not a part of base R but of a package, a concept which we will cover Chapter 7. To get more info on control structure, read Chapter 13 of R Programming for Data Science by Roger D Peng.

6.1 if, else, and ifelse

The if statement is exactly as it sounds:

if …. then do ……

The syntax of if statement is written as: if() with the condition or test in the bracket then {}, the expression of what should happen if the condition in the parentheses is passed is written in the curly braces. In simple terms we can relate it as if a certain condition is met then do the following:

if (condition) {
  expression
}

For example let’s multiply a number by 2 if its greater than 5.

x <- 10

if (x > 5) {
  x * 2
}
[1] 20

The if statement only does something when one result of the condition, TRUE, is met, and does nothing when the result equates to FALSE. If x is lesser than 5 we won’t get a result because x did not pass the test.

x <- 3
if (x > 5) {
  x * 2
}

This is when the else clause comes in handy to give results when the test in the if are FALSE. It is important to note that the if clause operates only on single element and the else clause is used in combination with the if clause. The syntax is now updated to look like the following:

if (condition) {
  expression_1
} else {
  expression_2
}

Let’s build on the previous last example to see how else works

x <- 15
if (x < 5)  {
  print(paste("The number", x, "is less than 5"))
} else {
  print(paste("The number", x, "is greater than 5"))
}
[1] "The number 15 is greater than 5"

As seen above, the else does not hold any condition, it simply handles all other conditions not handled by the if statement. If you want to introduce more structure to your code, testing more than two conditions you can use the else if clause. The else if comes after the if clause, the syntax is shown below:

if (condition) {
  expression_1
} else if (condition) {
  expression_2
} else {
  expression_3
}
x <- 10

if (x > 10) {
  print(paste("The number", x, "is greater than 10"))
} else if (x == 10) {
  print("The number is exactly 10")
} else {
  print(paste("The number", x, "is less than 10"))
}
[1] "The number is exactly 10"

There’s a show form of the if and else statement, the ifelse(), and it takes the following syntax

ifelse(test_or_condition, result_if_true, result_if_false)

For example:

x <- 11
ifelse(x == 10, x - 2, x + 2)
[1] 13

Since x is not equal to 10, the expression when false is executed. while all the different methods of the if-else statement works, they can lead to a long chain of command, which can be difficult to follow. An alternative method is to use switch or case_when() of dplyr package. case_when() is an inspiration from SQL and won’t be covered now but used as we progress. However, the syntax is given below:

case_when(
  condition_1 ~ result/expression,
  condition_2 ~ result_2/expression,
  .default = default_result/default_expression
)

6.2 for Loops

for loops are used for iterating over elements of objects such as list, vector, matrices, and so on (Peng 2016). The syntax of the for is straightforward. It takes the for clause, an iterator and an object covered in parenthesis and a curly bracket which takes the expression of what you want to do on the iteration of elements of the object.

for (iterator in object) {
  expression
}

Let’s deconstruct the parts of the for loop:

  • for: The keyword that initiates the loop structure.
  • iterator: A variable that takes on the value of each element in the object sequentially during each iteration of the loop. You can choose any valid variable name for the iterator.
  • object: This is the sequence (like a vector, list, or other iterable structure) over which the loop will iterate. The loop will run once for each element contained within this object.
  • expression: This is the block of code enclosed in curly braces {} that will be executed for each value assigned to the iterator. This is where you put the actions you want to perform on each element (or based on each element) of the object.

In simple terms, the for loop goes through each item in the object, assigns that item’s value to the iterator variable, and then runs the expression using that iterator value, repeating until all items in the object have been processed. Let’s take the example below:

num <- 1:10

for (i in num){
  print(i + 3)
}
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10
[1] 11
[1] 12
[1] 13

i here is the iterator and takes each element, and in each iteration of the loop it given the values 1, 2, 3, …, 10. For the first iteration where i is equal to 1, the expression print(i + 3) is executed and result given as 4 (1 + 3). The code is started again for the next value, 2, and now i is equal to 2. The expression is repeated again print(i + 3) and result is given as 5 (2 + 3). This repeated continuously until the end of the loop.

It is not uncommon to use some functions such seq_along(), length() in the for loop in order to generate a sequence based on the object.

set.seed(123)

my_num <- runif(10, min = -1, max = 1)

for (i in seq_along(my_num))  {
  print(my_num[i])
}
[1] -0.424845
[1] 0.5766103
[1] -0.1820462
[1] 0.7660348
[1] 0.8809346
[1] -0.908887
[1] 0.05621098
[1] 0.7848381
[1] 0.10287
[1] -0.08677053
for (i in 1:length(my_num)) {
  print(my_num[i])
}
[1] -0.424845
[1] 0.5766103
[1] -0.1820462
[1] 0.7660348
[1] 0.8809346
[1] -0.908887
[1] 0.05621098
[1] 0.7848381
[1] 0.10287
[1] -0.08677053

The iterator can be given any name as long as it follows variable naming conventions, but it is advised to use the name that reflects the objects in the collection. For example:

Object Iterator
fruits fruit
names name
cities city
products product

They are common stand in iterator variables popular in the programming world such as i, j or k.

6.2.1 Nesting the for Loop

You can nest for loops inside each other. In this case indent your code, so you can understand the flow of your code. An example is given below:

x <- 20
y <- 1:10
for (i in seq_len(x)) {
  z <- ""
  for (j in seq_along(y)) {
    z <- j * 2
  }
  a <- z + i
  print(a)
}
[1] 21
[1] 22
[1] 23
[1] 24
[1] 25
[1] 26
[1] 27
[1] 28
[1] 29
[1] 30
[1] 31
[1] 32
[1] 33
[1] 34
[1] 35
[1] 36
[1] 37
[1] 38
[1] 39
[1] 40

6.3 while Loop

while() loops test a condition and keeps iterating until they are FALSE and then exits the loop.

x <- 0

while (x < 10) {
  print(paste("The value of x was", x))
  x = x + 1
  print(paste("The value of x is now", x))
}
[1] "The value of x was 0"
[1] "The value of x is now 1"
[1] "The value of x was 1"
[1] "The value of x is now 2"
[1] "The value of x was 2"
[1] "The value of x is now 3"
[1] "The value of x was 3"
[1] "The value of x is now 4"
[1] "The value of x was 4"
[1] "The value of x is now 5"
[1] "The value of x was 5"
[1] "The value of x is now 6"
[1] "The value of x was 6"
[1] "The value of x is now 7"
[1] "The value of x was 7"
[1] "The value of x is now 8"
[1] "The value of x was 8"
[1] "The value of x is now 9"
[1] "The value of x was 9"
[1] "The value of x is now 10"

When using the while loop, the object value should always be updated to ensure there’s an end to the loop. In the example above, x keeps updating until it reaches the condition where FALSE is the result. Without the object updating, the loop will continue forever.

Use the while loop with care, if not used with care, the code will keep running till infinity. You can break this infinite loop with CTRL/CMD+C

6.4 switch

switch is used to select to select one of several alternatives based on the value of an expression. It’s like an ifelse() statement but more concise. switch are used in two ways depending on their first argument.

  • a character strung to match, or
  • an integer index position to match

The syntax of switch is given below:

switch (object,
  case = action
)

The case = action argument can be repeated multiple times.

x <- "a"

switch (x,
  a = "Man",
  b = "Woman",
  c = "boy",
  d = "girl"
)
[1] "Man"

Let’s take an example using the integer index position

y <- 3

switch(y,
   "Apple",
   "Mango",
   "Clementine"
)
[1] "Clementine"

If there’s no match for the object, NULL is returned. we can add a default option to return to by adding a value at the end that doesn’t match any case name

x <- "dog"

switch(x,
  man = "tade",
  woman = "sarah",
  boy = "zee",
  "bruno"
  
)
[1] "bruno"

6.5 Bringing it all together

6.6 Summary

Control structures in R are essential tools that allow you to direct the flow of execution in your code based on conditions or repetitions. They help make your code dynamic, responsive, and efficient by avoiding redundancy and enabling decision-making. In this chapter, you explored:

  • Conditional statements like if, else, and ifelse() that let you run different code depending on whether a condition is true or false.

  • The switch() function, which provides a cleaner way to select one of many alternatives based on a matching value or position.

  • Loops such as for and while, which repeat actions across multiple elements or until a condition is no longer met.

  • How to nest loops and use helper functions like seq_along() and length() to control iteration.

  • The importance of updating conditions in loops to avoid infinite execution.

Together, these structures form the building blocks for writing programs that can automate tasks, process data, and respond intelligently to varying inputs in your research workflow.