Introduction to R: Lecture 9

Topics: Conditional Statements with if, else, and else if

Sabrina Nardin, Summer 2025

Agenda

  1. Overview of Control Structures: Conditional Statements and Loops
  2. Deeper Dive into Conditional Statements

These slides were last updated on July 29, 2025

1. Overview of Control Structures

Control Structures: What’s the Idea?

Up to this point, our R code has been running line by line following in a fixed sequence.


Now we ask: Can our code be dynamic vs fixed?

For Example: Can it skip some lines and run others depending on a condition? Or can it repeat itself when needed?

Yes, with control structures!


What Are Control Structures?

Control structures let us write code that can:

  • Make decisions
    → with conditional statements (if, if...else, etc.)

  • Repeat actions
    → with loops (for, while)

Conditional statements and loops — that is, control structures — let us control the flow of execution. They allow our code to respond dynamically to different situations, rather than always running in the same fixed order like we’ve done so far.

2. Deeper Dive into Conditional Statements

Conditional Statements

Conditional statements let our code make decisions: the code checks conditions, evaluates them, and chooses what to do.

Said more formally, we use logical tests to determine which code should run:

  1. Single test with if... else

  2. Multiple tests with if... else if... else

  3. Nested tests by placing one if inside another

  4. Vectorized tests with ifelse() (or if_else() in tidyverse) to apply a condition to each element of a vector

💻 Practice

  1. Download today’s class materials from the course website.

  2. Open the file called warm-up.R.

  3. Before running the code: look over the syntax and try to predict what the code will output

  4. Run the code and compare it to your prediction.

  5. Be ready to share at least one question about what the code.

1. Single test with if… else

Use if...else when your code needs to test one condition and take one of two possible actions, depending on whether the condition is TRUE or FALSE.

Syntax:

if (condition) {
    # action performed when condition is TRUE
    action1
} else {
    # action performed when condition is FALSE
    action2
}

Example:

age <- 14

if (age > 16) {
  print("You can get a driving license")
} else {
  print("You cannot drive")
}

1. Single test with if… else

Another Example: What’s the output of this code?

movie_rating <- c(4.5, 4.2, 5.0, 3.8, 2.9, 1.7)
movie_avg_rating <- mean(movie_rating)

if (movie_avg_rating >= 4) {
  print("This movie is great!")
} else {
  print("Not a favorite.")
}

2. Multiple tests with if… else if… else

Use if...else if...else when your code needs to test multiple conditions and take different actions depending on which condition is TRUE.

Syntax:

if (condition1) {
    # action performed when condition 1 is TRUE
    action1
} else if (condition2) {
    # action performed when condition 2 is TRUE
    action2
} else {
    # action performed when conditions 1 and 2 are FALSE
    action3
}

Example:

x <- 0

if (x > 0) {
  print("x is positive")
} else if (x < 0) {
  print("x is negative")
} else {
  print("x is zero")
}

Note: with conditional statements sequence matters!

Conditional statements are evaluated in order so the sequence of your code matters:

  • R checks each condition one by one, from top to bottom
  • As soon as it finds a condition that is TRUE, it runs that block and skips the rest

2. Multiple tests with if… else if… else

Another Example with multiple else if statements:

# Take user input
temperature <- as.integer(readline(prompt = "Enter today's temperature in Celsius: "))

# Determine weather based on temperature
if (temperature >= 30) {
  weather <- "Hot"
} else if (temperature >= 20) {
  weather <- "Cool"
} else if (temperature >= 10) {
  weather <- "Breezy"
} else {
  weather <- "Freezing"
}
print(weather)

💻 Practice

  1. What happens if the conditions are out of order? Move temperature >= 10 before temperature >= 20 in the code and run it with temperature 25
  1. Add another else if statement to further refine the code: If the temperature is between 0 and 10 (inclusive of 0, exclusive of 10), set the weather to “Cold”. Hint: use the & operator to combine two conditions.

Once done, share your code here.

3. Nested tests by placing one if inside another

Use nested if...else statements when your code needs to check conditions within conditions. This allows you to make a second decision only after a first condition is met.

Example (note the %% returns the remainder after division):

x <- 15

if (x > 0) {
  if (x %% 2 == 0) {
    print("x is a positive even number")
  } else {
    print("x is a positive odd number")
  }
} else {
  if (x %% 2 == 0) {
    print("x is a negative even number")
  } else {
    print("x is a negative odd number")
  }
}

3. Nested tests by placing one if inside another

Same example, but this checks also the condition x <- 0:

x <- 0

if (x > 0) {
  if (x %% 2 == 0) {
    print("x is a positive even number")
  } else {
    print("x is a positive odd number")
  }
} else if (x < 0) {
  if (x %% 2 == 0) {
    print("x is a negative even number")
  } else {
    print("x is a negative odd number")
  }
} else {
  print("x is zero")
}

4. Vectorized tests with ifelse()

Use ifelse() to apply a condition to each element of a vector. This is called a “vectorized test”, and fits well R’s vector-based design.

Syntax:

ifelse (condition to be evaluated,
    action performed when condition is TRUE,
    action performed when condition is FALSE)

Example:

y <- 3

ifelse(sqrt(16) > y, 
       sqrt(16),
       0)

4. Vectorized tests with ifelse()

Another example: What is the output of this code?

numbers <- c(10, 6, 7)
ifelse(numbers %% 2 == 1, 
       "odd",
       "even")


How ifelse() works:

  • The input to ifelse() is often a vector, not just a single value, so the output is also a vector. The code evaluates each element of the vector, applying the specified action for each case.

  • This works because ifelse() supports vectorized operations: operations directly applied on entire vectors, rather than looping through individual elements one-by-one.

4. Vectorized tests with ifelse()

Example: What is the output of this code?

library(tidyverse)

qualify <- tibble("Athlet" = c("Noah", "Julio", "Nick", "Maria"), 
                  "Scores" = c(32, 37, 28, 30))

# using base R to access column Scores
ifelse(qualify$Scores > 30, 
       "Admitted", 
       "Rejected")

# using dplyr
qualify %>%
  mutate(status = ifelse(Scores > 30,
                       "Admitted",
                       "Rejected"))

4. Vectorized tests with ifelse()

In the previous example, we only had two possible categories: “Admitted” and “Rejected”

What happens to our code if we add a third one, say “Waitlisted”?

qualify <- tibble("Athlet" = c("Noah", "Julio", "Nick", "Maria"), 
                  "Scores" = c(32, 37, 28, 30))

qualify %>%
  mutate(Status = ifelse(Scores > 35,            # first condition
                         "Admitted",             # if TRUE
                         ifelse(Scores >= 30,    # second condition (only if first is FALSE)
                                "Waitlisted",    # if TRUE
                                "Rejected")))    # if both FALSE

4. Vectorized tests with ifelse()

Nested ifelse() statements work, but they make the code harder to read.

Compare the previous code with this code that does not use them:

qualify <- tibble("Athlet" = c("Noah", "Julio", "Nick", "Maria"), 
                  "Scores" = c(32, 37, 28, 30))

qualify %>%
  mutate(Status = "Rejected") %>%                                  # default label
  mutate(Status = ifelse(Scores >= 30, "Waitlisted", Status)) %>%  # update if condition met
  mutate(Status = ifelse(Scores > 35, "Admitted", Status))         # update if higher condition met


Tip

If you have multiple conditions (more than two):

  • Write several separate mutate() + ifelse() steps, as shown on this slide, rather than nesting them, as shown on the previous slide

  • When possible, use case_when() instead of ifelse() for better readability


4. Vectorized tests with ifelse()

People often use ifelse() to recode variables in a dataframe. It’s a good choice when the recoding can be done with a single ifelse(), as shown in this example.

Example: the variable decisionDirection takes four values (1 conservative, 2 liberal, 3 unspecifiable, and NA). Recode it to take three values (0 conservative, 1 liberal, and NA for both NA and unspecifiable)

data %>%
  mutate(decisionDirection = ifelse(
    decisionDirection == 3, # condition to be evaluated
    NA,                     # if true, do NA
    decisionDirection - 1   # if false, subtract one to value
    ))

4. Vectorized tests with ifelse()

Note there is also a tidyverse version of the base R ifelse() function!

The tidyverse version is called if_else() https://dplyr.tidyverse.org/reference/if_else.html

The two are similar, hence I introduced only on here, pick the one you prefer.

💻 Practice

You can fine more practice exercises in today’s class materials (downloaded from the website)

Recap: What We Learned Today

  • Control structures let us change the flow of execution in our code
  • We focused on conditional statements: how to make decisions using if, else, and else if
  • We practiced different types of conditionals:
    • single test, multiple tests, and nested tests
    • vectorized tests with ifelse() and if_else()

To print these slides as pdf

Click on the icon bottom-right corner > Tools > PDF Export Mode > Print as a Pdf