Skip to content

R - Loops

R - Control Flow: Loops and Their Modern Alternatives

Section titled “R - Control Flow: Loops and Their Modern Alternatives”

In programming, we often need to repeat a task multiple times. Loops allow us to execute a block of code repeatedly. While R has traditional loops similar to other languages, it also offers more efficient and readable alternatives like vectorization and functional programming, which are often preferred.

This tutorial covers the standard loops (for, while, repeat) and then introduces the modern, ‘R-native’ ways to handle repetitive tasks.

A for loop iterates over each item in a sequence (like a vector or list). It’s useful when you know exactly how many times you need to iterate.

# A for loop that iterates through a vector of numbers
for (i in 1:5) {
# The code inside the curly braces is the 'loop body'
print(paste("The current number is:", i))
}
# Output:
# [1] "The current number is: 1"
# [1] "The current number is: 2"
# ... and so on up to 5

A while loop repeats as long as a specified condition is TRUE. It’s useful when you don’t know the exact number of iterations in advance.

counter <- 1
while (counter <= 5) {
print(paste("Counter is at:", counter))
counter <- counter + 1 # CRITICAL: You must change the condition variable inside the loop!
}
# Output:
# [1] "Counter is at: 1"
# [1] "Counter is at: 2"
# ... and so on up to 5

Common Error: Forgetting to update the variable in the while condition (like counter <- counter + 1) will result in an infinite loop that will crash your R session.

A repeat loop creates an infinite loop by default. You must provide an explicit break statement to exit it. It’s less common but can be useful when the exit condition is complex and best checked in the middle of the loop.

counter <- 1
repeat {
print(paste("Repeat loop counter:", counter))
if (counter >= 5) {
break # Exit the loop
}
counter <- counter + 1
}
  • break: Immediately terminates the entire loop.
  • next: Skips the rest of the current iteration and proceeds to the next one.
# Example of 'next' and 'break'
for (i in 1:10) {
if (i %% 2 != 0) {
next # Skip odd numbers
}
if (i > 8) {
break # Stop if the number is greater than 8
}
print(i)
}
# Output:
# [1] 2
# [1] 4
# [1] 6
# [1] 8

The ‘R Way’: Modern Alternatives to Loops

Section titled “The ‘R Way’: Modern Alternatives to Loops”

In R, loops can be slow, especially with large datasets. R’s strength lies in vectorization and functional programming, which are faster and often more concise.

Vectorization means applying an operation to an entire vector at once, rather than element by element. R is highly optimized for this.

my_numbers <- c(10, 20, 30, 40, 50)
# The slow, loop-based way
result_loop <- numeric(length(my_numbers))
for (i in 1:length(my_numbers)) {
result_loop[i] <- my_numbers[i] * 2
}
# The fast, vectorized R way
result_vectorized <- my_numbers * 2
# Both produce the same result, but the vectorized way is far superior.
# result_vectorized is c(20, 40, 60, 80, 100)

2. Functional Programming: The purrr::map Family

Section titled “2. Functional Programming: The purrr::map Family”

When you need to apply a more complex function to each element of a list or vector, the map() functions from the purrr package (part of the tidyverse) are the modern standard. They are more consistent and predictable than base R’s apply family.

library(purrr)
my_list <- list(a = 1:5, b = c(10, 20), c = 100)
# Use map() to get the mean of each element. The result is a list.
list_of_means <- map(my_list, mean)
# Result: list(a = 3, b = 15, c = 100)
# Use map_dbl() to get the mean and return a numeric vector.
vector_of_means <- map_dbl(my_list, mean)
# Result: c(a = 3, b = 15, c = 100)

Strive to use vectorized operations or purrr::map whenever possible. However, for loops are still perfectly fine and necessary in certain situations:

  • Sequential Dependencies: When the result of one iteration depends on the result of the previous one (e.g., in some simulations).
  • Side Effects: When the primary purpose of the loop is a side effect, like printing to the console, plotting charts, or saving files.
  • Complex Logic: When the logic is too complex to fit neatly into a vectorized or functional form, a loop can be more readable.