R Conditionals — if/else, switch, and Vectorized Conditionals

R BasicsConditionalsFree Lesson

Advertisement

R Conditionals — if/else, switch, and Vectorized Conditionals

Learning Objectives

By the end of this tutorial, you will be able to:

  • Use if/else for single and chained conditions
  • Apply ifelse() for vectorized conditional operations
  • Use switch() for multi-way branching
  • Work with case_when() for complex vectorized conditions
  • Understand vectorized vs scalar conditionals

if/else Statements

Basic if

x <- 10

if (x > 5) {
  cat("x is greater than 5\n")
}
# x is greater than 5

if/else

x <- 3

if (x > 5) {
  cat("x is greater than 5\n")
} else {
  cat("x is 5 or less\n")
}
# x is 5 or less

Chained if/else if/else

score <- 85

if (score >= 90) {
  grade <- "A"
} else if (score >= 80) {
  grade <- "B"
} else if (score >= 70) {
  grade <- "C"
} else if (score >= 60) {
  grade <- "D"
} else {
  grade <- "F"
}

cat("Grade:", grade, "\n")
# Grade: B

One-Liner if/else

x <- 10
result <- if (x > 5) "big" else "small"
result  # [1] "big"

# Equivalent to
if (x > 5) result <- "big" else result <- "small"

ifelse() — Vectorized Conditional

ifelse() works element-wise on vectors:

x <- c(1, 5, 10, 15, 20)

ifelse(x > 10, "big", "small")
# [1] "small" "small" "small" "big"   "big"

# With NA handling
x <- c(1, NA, 10, NA, 20)
ifelse(is.na(x), 0, x)
# [1]  1  0 10  0 20

# Nested ifelse
score <- 85
grade <- ifelse(score >= 90, "A",
         ifelse(score >= 80, "B",
         ifelse(score >= 70, "C",
         ifelse(score >= 60, "D", "F"))))
grade  # [1] "B"

ifelse() vs if/else

Featureif/elseifelse()
ScalarYesNo
VectorizedNoYes
SpeedSlower for vectorsFaster for vectors
Return TypeAnySame type as test
# WRONG — only tests first element
x <- c(1, 5, 10, 15, 20)
if (x > 10) "big" else "small"
# Warning: the condition has length > 1 and only the first element will be used

# RIGHT — vectorized
ifelse(x > 10, "big", "small")
# [1] "small" "small" "small" "big"   "big"

switch() — Multi-Way Branching

# By position
x <- 2
switch(x,
  "first",
  "second",
  "third",
  "fourth"
)
# [1] "second"

# By name
x <- "apple"
switch(x,
  apple = "red",
  banana = "yellow",
  grape = "purple",
  "unknown"
)
# [1] "red"

# Default value
x <- "unknown_fruit"
switch(x,
  apple = "red",
  banana = "yellow",
  grape = "purple",
  "unknown"  # Default (no name)
)
# [1] "unknown"

# In function
calculate <- function(op, x, y) {
  switch(op,
    add = x + y,
    subtract = x - y,
    multiply = x * y,
    divide = if (y != 0) x / y else "Cannot divide by zero",
    "Unknown operation"
  )
}

calculate("add", 10, 5)       # [1] 15
calculate("multiply", 10, 5)  # [1] 50
calculate("power", 10, 5)     # [1] "Unknown operation"

case_when() — Tidyverse Multi-Condition

library(dplyr)

x <- c(1, 5, 10, 15, 20, 25)

case_when(
  x < 5 ~ "low",
  x < 15 ~ "medium",
  x < 25 ~ "high",
  TRUE ~ "very high"
)
# [1] "low"      "medium"   "medium"   "high"     "high"     "very high"

# With data frames
df <- data.frame(score = c(85, 92, 78, 95, 88))
df |>
  mutate(grade = case_when(
    score >= 90 ~ "A",
    score >= 80 ~ "B",
    score >= 70 ~ "C",
    score >= 60 ~ "D",
    TRUE ~ "F"
  ))

case_match() — Exact Matching (R 4.2+)

x <- c("a", "b", "c", "d")
case_match(x,
  "a" ~ "apple",
  "b" ~ "banana",
  .default = "other"
)
# [1] "apple"  "banana" "other"  "other"

Nested and Complex Conditions

# Nested if/else
x <- 15
y <- 20

if (x > 10) {
  if (y > 15) {
    result <- "both big"
  } else {
    result <- "only x big"
  }
} else {
  if (y > 15) {
    result <- "only y big"
  } else {
    result <- "neither big"
  }
}
result  # [1] "both big"

# Compound conditions
age <- 25
income <- 50000

if (age >= 18 && income >= 30000) {
  cat("Eligible for loan\n")
}

# Multiple conditions
x <- 10
if (x > 5 && x < 15 && x != 10) {
  cat("Condition met\n")
} else {
  cat("Condition not met\n")
}
# Condition not met

Vectorized vs Scalar

# Scalar: if/else
x <- 10
if (x > 5) "big" else "small"

# Vectorized: ifelse
x <- c(1, 5, 10, 15, 20)
ifelse(x > 5, "big", "small")

# Vectorized: case_when
x <- c(1, 5, 10, 15, 20)
case_when(
  x < 5 ~ "small",
  x < 15 ~ "medium",
  TRUE ~ "large"
)

# Vectorized: dplyr
df <- data.frame(x = c(1, 5, 10, 15, 20))
df |>
  mutate(category = case_when(
    x < 5 ~ "small",
    x < 15 ~ "medium",
    TRUE ~ "large"
  ))

Practice Exercises

Exercise 1: Grade Calculator

Write a function that takes a numeric score (0-100) and returns the letter grade using if/else.

Solution

grade_calc <- function(score) {
  if (score >= 90) {
    "A"
  } else if (score >= 80) {
    "B"
  } else if (score >= 70) {
    "C"
  } else if (score >= 60) {
    "D"
  } else {
    "F"
  }
}

grade_calc(85)  # [1] "B"
grade_calc(92)  # [1] "A"
grade_calc(55)  # [1] "F"

Exercise 2: Vectorized Category

Given x <- c(1, 5, 10, 15, 20, 25, 30), create a vector of categories: "low" (less than 10), "medium" (10-20), "high" (greater than 20).

Solution

x <- c(1, 5, 10, 15, 20, 25, 30)

# Using ifelse (nested)
categories <- ifelse(x < 10, "low",
              ifelse(x <= 20, "medium", "high"))
categories

# Using case_when (cleaner)
library(dplyr)
case_when(
  x < 10 ~ "low",
  x <= 20 ~ "medium",
  TRUE ~ "high"
)

Key Takeaways

  • if/else is for scalar (single value) decisions
  • ifelse() is vectorized — works on entire vectors
  • switch() is for multi-way branching by value
  • case_when() is the tidyverse alternative for complex conditions
  • R is vectorized — prefer ifelse() and case_when() over loops
  • if/else only tests the first element of a vector (with warning)
  • Use TRUE ~ as default in case_when()

Next: Learn about R Loops — for, while, and repeat loops.

Advertisement

Need Expert R Programming Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement