6 Conditional Statements

The control flow of an R program is regulated by two key constructs: conditional statements and loops. Conditional statements, like if statements, allow code to run only when a condition is met. Loops, like for and while, allow code to run repeatedly.

This chapter focuses on the conditional statements. They are the building blocks that let a program respond differently depending on the data it encounters.

6.1 What Ifs

if

The simplest form of control flow is if conditional statements. if takes a logical vector of length one. If the condition is TRUE, the statement gets executed. If the condition is FALSE, if invisibly returns NULL.

How it works:

if (condition) {
  statement
}

Note: Wrap the statement(s) in a pair of curly braces { }.

Example:

x <- 6

if (x > 5) {
  print(paste(x, "is larger than 5."))
}
## [1] "6 is larger than 5."

Note: When there is only a single statement, the braces may be omitted.

How it works:

if (condition) statement

Example:

x <- 6

if (x > 5) print( paste(x, "is larger than 5.") )
## [1] "6 is larger than 5."

ifelse

An if statement alone does nothing when its condition is FALSE.

x <- 5

if (x > 5) print( paste(x, "is larger than 5.") )

To handle that case explicitly, add an else clause: a fallback that runs whenever the if condition is not met.

How it works:

if (condition) {
  true statement
} else {
  false statement
}

Example:

x <- 5

if (x > 5) {
  print( paste(x, "is larger than 5.") )
} else {
  print( paste(x, "is not larger than 5.") )
}
## [1] "5 is not larger than 5."

ifelse if

When there are more than two cases, chain additional conditions using else if. else if is essentially saying “if the previous condition is not true, then try this condition”.

How it works:

if (condition) {
  statement
} else if (condition) {
  statement
} 

Example:

x <- 3

if (x > 5) {
  print( paste(x, "is larger than 5.") )
} else if (x < 5) {
  print( paste(x, "is smaller than 5.") )
}
## [1] "3 is smaller than 5."

Multiple else if clauses can be chained.

How it works:

if (condition) {
  statement
} else if (condition) {
  statement
} else if (condition) {
  statement
}

ifelse ifelse

To ensure every possible case is handled, end the chain with a bare else. else executes when all preceding conditions are FALSE.

How it works:

if (condition) {
  statement
} else if (condition) {
  statement
} else {
  statement
}

Example:

x <- 1

if (x > 5) {
  print( paste(x, "is larger than 5.") )
} else if (x == 5) {
  print( paste(x, "is equal to 5.") )
} else {
  print( paste(x, "is smaller than 5.") )
}
## [1] "1 is smaller than 5."

Note: The else keyword must appear on the same line as the closing curly brace } from the if clause.

Exercise

Write an R program to convert month name to a number of days. For instance, if we input “February”, then the output will be “No. of days: 28 or 29 days”.

Hint: Use readline(), which reads a line from the terminal in interactive use.

month <- readline("Input a month name: ")
month_30 <- c("April", "June", "September", "November")
month_31 <- c("January", "March", "May", "July", "August", "October", "December")

if (month %in% month_30){
  print("No. of days: 30 days") 
} else if (month %in% month_31){
  print("No. of days: 31 days")
} else if (month == "February") {
  print("No. of days: 28 or 29 days")
} else {
  print("Incorrect input")
}

This exercise practices building an ifelse ifelse chain to classify one input into several categories. The program checks whether the month belongs to the 30-day group, the 31-day group, or is "February", and uses else to catch invalid input. It also reinforces the use of %in% for testing membership in a set of values.

6.2 Nested if

if statements can be placed inside other if statements. This is called nesting.

Nested if statements are useful when a second condition only makes sense to check after a first condition has already been confirmed.

Example:

x <- 9

if (x > 5) {
  print(paste(x, "is larger than 5,"))
  if (x > 10) {
    print(paste("and also larger than 10."))
  } else {
    print("but not larger than 10.")
  }
} else {
  print(paste(x, "is not larger than 5."))
}
## [1] "9 is larger than 5,"
## [1] "but not larger than 10."

Exercise

Write an R program to find the median of three integers. Do not use the built-in function median().

a <- as.integer(readline("Input the 1st number: "))
b <- as.integer(readline("Input the 2nd number: "))
c <- as.integer(readline("Input the 3rd number: "))

if (a > b){
  if (b > c) { print(b) }
  else if (c > a) { print(a) } 
  else { print(c) }
} else {
  if (a > c){ print(a) }
  else if (c > b){ print(b) } 
  else{ print(c) }
} 

This exercise practices nested if statements by breaking the problem into a sequence of comparisons. First, the program compares a and b to determine which one is larger. Once that relationship is known, it checks the third number, c, against them to see whether c is the largest, the smallest, or the one in between. In this way, each if block narrows down the possibilities until the number that lies between the other two is found, which is exactly the median.

6.3 Vectorized ifelse()

Recall that if only takes a logical vector of length one. If we pass a logical vector with a length of more than one, e.g., if(c(TRUE, FALSE)), we will receive an error.

if(c(TRUE, FALSE)) print("!")
## Error in `if (c(TRUE, FALSE)) ...`:
## ! the condition has length > 1

What if we have multiple logical values? There is a vectorized version of the if ... else ... construct, the ifelse() function, which handles a vector of logical values element by element.

How it works:

ifelse(test, yes, no)

ifelse() takes three arguments. The first argument is a logical vector of conditions. The second argument contains values that are returned where condition is TRUE. The third argument contains values that are returned where condition is FALSE.

It returns a vector of the same length as the condition test. This means: yes[i] if test[i] is TRUE, otherwise no[i]. yes and no are recycled where necessary.

Example:

In the example below, x is a vector containing multiple values. The object test checks whether each element of x is greater than 5. For each position, ifelse() returns the corresponding value from yes when the condition is TRUE, and the corresponding value from no when the condition is FALSE.

x <- 1:15

test <- x > 5
yes <- paste(x, "is larger than 5")
no <- paste(x, "is not larger than 5")

ifelse(test, yes, no)
##  [1] "1 is not larger than 5" "2 is not larger than 5" "3 is not larger than 5"
##  [4] "4 is not larger than 5" "5 is not larger than 5" "6 is larger than 5"    
##  [7] "7 is larger than 5"     "8 is larger than 5"     "9 is larger than 5"    
## [10] "10 is larger than 5"    "11 is larger than 5"    "12 is larger than 5"   
## [13] "13 is larger than 5"    "14 is larger than 5"    "15 is larger than 5"

A more realistic example could be assigning pass or fail labels to a set of test scores.

scores <- c(92, 76, 58, 45, 84)
result <- ifelse(scores >= 60, "Pass", "Fail")

data.frame(score = scores, result = result)
##   score result
## 1    92   Pass
## 2    76   Pass
## 3    58   Fail
## 4    45   Fail
## 5    84   Pass

Here, the condition scores >= 60 is evaluated for each score. If the condition is TRUE, ifelse() returns "Pass"; otherwise, it returns "Fail". The result is a vector with one label for each score, in the same order as the original vector.