JSTAcademy
0 XP
Dashboard
Crash Courses
Control Flow & Functions
16 min
Masters+170 XP
Crash Courses · Masters

Control Flow & Functions

Write if/else, for and while loops in R, and build reusable functions with default arguments, return values, and proper documentation.
16 min read+170 XP on completionCert: R Crash Course
Tap any word in the text below to start reading from there.

Control Flow & Functions

if / else

# Scalar if (single TRUE/FALSE)
x <- 15

if (x > 10) {
  cat("Greater than 10\n")
} else if (x == 10) {
  cat("Equal to 10\n")
} else {
  cat("Less than 10\n")
}

# Compact form (single expressions)
result <- if (x > 0) "positive" else "non-positive"

# ifelse() — vectorized (processes every element)
scores <- c(92, 78, 85, 61, 95)
grades <- ifelse(scores >= 90, "A",
          ifelse(scores >= 80, "B",
          ifelse(scores >= 70, "C", "F")))
print(grades)  # "A" "C" "B" "F" "A"

---

Loops

# for loop
fruits <- c("apple", "banana", "cherry")
for (fruit in fruits) {
  cat(toupper(fruit), "\n")
}

# for with index
for (i in 1:5) {
  cat(sprintf("Item %d: %.2f\n", i, i^2))
}

# while loop
n <- 1
while (n < 100) {
  n <- n * 2
}
cat("First power of 2 >= 100:", n, "\n")  # 128

# next (continue) and break
for (i in 1:10) {
  if (i %% 2 == 0) next   # skip even numbers
  if (i > 7) break         # stop when i > 7
  cat(i, "")
}
# Output: 1 3 5 7

Important: R loops are slow. Prefer vectorized operations for data processing — use loops only for truly sequential logic.

---

Functions

# Basic function
square <- function(x) {
  x ^ 2  # implicit return — last expression is returned
}

square(5)   # 25
square(1:5) # c(1, 4, 9, 16, 25) — vectorized automatically

# Default arguments
greet <- function(name, greeting = "Hello", punctuation = "!") {
  paste0(greeting, ", ", name, punctuation)
}

greet("Jordan")                     # "Hello, Jordan!"
greet("Alice", greeting = "Hi")     # "Hi, Alice!"
greet("Bob", punctuation = ".")     # "Hello, Bob."

# Multiple return values (use a list or named vector)
stats_summary <- function(x) {
  list(
    mean   = mean(x, na.rm = TRUE),
    median = median(x, na.rm = TRUE),
    sd     = sd(x, na.rm = TRUE),
    n      = sum(!is.na(x))
  )
}

result <- stats_summary(c(3, 7, NA, 2, 9, 1, 8))
cat("Mean:", result$mean, "\n")
cat("Median:", result$median, "\n")
cat("N (non-NA):", result$n, "\n")

---

Input Validation and Error Handling

safe_divide <- function(a, b) {
  if (!is.numeric(a) || !is.numeric(b)) {
    stop("Both arguments must be numeric")  # fatal error
  }
  if (b == 0) {
    warning("Division by zero — returning Inf")
    return(Inf)
  }
  a / b
}

# tryCatch for error handling
result <- tryCatch({
  safe_divide(10, 0)
}, warning = function(w) {
  message("Warning caught: ", conditionMessage(w))
  NA  # return NA on warning
}, error = function(e) {
  message("Error: ", conditionMessage(e))
  NA
})

---

Functional Idioms: lapply, sapply, Map, Reduce

# lapply — apply function to list, returns list
nums <- list(a = 1:5, b = 6:10, c = 11:15)
lapply(nums, mean)  # list(a=3, b=8, c=13)

# sapply — simplify result to vector/matrix
sapply(nums, mean)   # named vector: a=3, b=8, c=13
sapply(nums, range)  # 2×3 matrix

# vapply — safer sapply with expected type
vapply(nums, mean, FUN.VALUE = numeric(1))  # guaranteed numeric vector

# Map — apply function to multiple vectors simultaneously
x <- c(1, 2, 3)
y <- c(10, 20, 30)
Map(function(a, b) a + b, x, y)  # list(11, 22, 33)
mapply(function(a, b) a + b, x, y)  # simplified: c(11, 22, 33)

# Reduce — fold a vector with a function
Reduce("+", 1:5)        # 15: ((((1+2)+3)+4)+5)
Reduce(max, c(3,1,4))   # 4

# Anonymous functions (R 4.1+: the \ shorthand)
sapply(1:5, \(x) x^2)   # c(1, 4, 9, 16, 25)
0%