R Loops — for, while, and repeat
Learning Objectives
By the end of this tutorial, you will be able to:
- Use
forloops to iterate over sequences and lists - Implement
whileandrepeatloops with proper termination - Control loop flow with
breakandnext - Understand when to use loops vs vectorized operations
- Apply
lapply,sapply, andvapplyas loop alternatives
for Loop
The for loop iterates over a sequence:
# Basic syntax
for (i in 1:5) {
cat("Iteration:", i, "\n")
}
# Iteration: 1
# Iteration: 2
# Iteration: 3
# Iteration: 4
# Iteration: 5
# Iterate over a vector
fruits <- c("apple", "banana", "cherry")
for (fruit in fruits) {
cat("I like", fruit, "\n")
}
# I like apple
# I like banana
# I like cherry
# Iterate over a list
x <- list(1, "hello", TRUE, 3.14)
for (item in x) {
cat(class(item), ":", item, "\n")
}
# numeric : 1
# character : hello
# logical : TRUE
# numeric : 3.14
Loop Patterns
# Sequence generation
for (i in seq(1, 10, by = 2)) {
cat(i, " ")
}
# 1 3 5 7 9
# Reverse order
for (i in 5:1) {
cat(i, " ")
}
# 5 4 3 2 1
# Using seq_along (index-based)
x <- c("a", "b", "c", "d")
for (i in seq_along(x)) {
cat("Element", i, ":", x[i], "\n")
}
# Element 1 : a
# Element 2 : b
# Element 3 : c
# Element 4 : d
# Using seq_len
for (i in seq_len(5)) {
cat(i, " ")
}
# 1 2 3 4 5
Accumulating Results
# Pre-allocate (fast)
result <- numeric(10)
for (i in 1:10) {
result[i] <- i^2
}
result
# [1] 1 4 9 16 25 36 49 64 81 100
# Growing vector (slow — avoid)
result <- c()
for (i in 1:10) {
result <- c(result, i^2) # Creates new copy each time!
}
while Loop
The while loop continues while a condition is TRUE:
# Basic while
x <- 1
while (x <= 5) {
cat(x, " ")
x <- x + 1
}
# 1 2 3 4 5
# Counting
count <- 0
total <- 0
while (total < 100) {
count <- count + 1
total <- total + count
}
cat("Needed", count, "numbers to exceed 100\n")
# Needed 14 numbers to exceed 100
# With break
x <- 1
while (TRUE) {
if (x > 10) break
cat(x, " ")
x <- x + 1
}
# 1 2 3 4 5 6 7 8 9 10
repeat Loop
The repeat loop runs indefinitely until break:
# Basic repeat
x <- 1
repeat {
if (x > 5) break
cat(x, " ")
x <- x + 1
}
# 1 2 3 4 5
# User input simulation
set.seed(42)
attempt <- 0
repeat {
attempt <- attempt + 1
guess <- sample(1:10, 1)
if (guess == 7) {
cat("Found 7 on attempt", attempt, "\n")
break
}
}
# Found 7 on attempt X (varies)
break and next
break — Exit Loop
# Find first even number
x <- c(1, 3, 5, 8, 9, 12)
for (i in x) {
if (i %% 2 == 0) {
cat("First even:", i, "\n")
break
}
}
# First even: 8
# Nested loop break
for (i in 1:5) {
for (j in 1:5) {
if (i * j > 10) {
cat("Breaking at i=", i, "j=", j, "\n")
break
}
}
}
next — Skip Iteration
# Skip odd numbers
for (i in 1:10) {
if (i %% 2 != 0) next
cat(i, " ")
}
# 2 4 6 8 10
# Skip specific values
x <- c("a", "b", "skip", "d", "skip", "f")
for (item in x) {
if (item == "skip") next
cat(item, " ")
}
# a b d f
Vectorized Alternatives (Preferred)
R is vectorized — loops are often unnecessary:
# Slow: loop
x <- 1:1000000
result <- numeric(length(x))
for (i in seq_along(x)) {
result[i] <- x[i]^2
}
# Fast: vectorized
result <- x^2
# Fast: apply family
result <- sapply(1:1000000, function(x) x^2)
lapply, sapply, vapply
# lapply — returns list
x <- list(1, 2, 3, 4, 5)
lapply(x, function(x) x^2)
# [[1]]
# [1] 1
# [[2]]
# [1] 4
# ...
# sapply — returns simplified result
x <- list(1, 2, 3, 4, 5)
sapply(x, function(x) x^2)
# [1] 1 4 9 16 25
# vapply — like sapply but with type safety
vapply(x, function(x) x^2, numeric(1))
# [1] 1 4 9 16 25
# With names
scores <- list(Alice = 95, Bob = 87, Charlie = 92)
sapply(scores, function(x) x * 1.1) # 10% bonus
# Alice Bob Charlie
# 104.50 95.70 101.20
apply Family Summary
| Function | Returns | Use Case |
|---|---|---|
lapply() | List | Always returns list |
sapply() | Vector/list | Simplified result |
vapply() | Vector/list | Type-safe sapply |
apply() | Vector/array | Apply over margins |
tapply() | List/array | Apply by group |
mapply() | Vector/list | Multivariate apply |
Common Loop Patterns
Nested Loops
# Matrix creation
n <- 5
m <- matrix(0, nrow = n, ncol = n)
for (i in 1:n) {
for (j in 1:n) {
m[i, j] <- i + j
}
}
m
# Or vectorized
m <- outer(1:5, 1:5, "+")
Loop with Counter
# Find convergence
x <- 1
iteration <- 0
repeat {
iteration <- iteration + 1
x <- x / 2 + 1/x
if (abs(x - sqrt(2)) < 1e-10) break
}
cat("Converged to", x, "in", iteration, "iterations\n")
Parallel Loops
# Using parallel package
library(parallel)
cl <- makeCluster(4)
result <- parLapply(cl, 1:100, function(x) x^2)
stopCluster(cl)
Practice Exercises
Exercise 1: Fibonacci
Write a for loop that generates the first 20 Fibonacci numbers.
Solution
fib <- numeric(20)
fib[1] <- 1
fib[2] <- 1
for (i in 3:20) {
fib[i] <- fib[i-1] + fib[i-2]
}
fib
# [1] 1 1 2 3 5 8 13 21 34 55 89 144 233
# [14] 377 610 987 1597 2584 4181 6765
Exercise 2: Prime Finder
Write a function that finds all prime numbers up to n using a for loop.
Solution
find_primes <- function(n) {
primes <- c()
for (i in 2:n) {
is_prime <- TRUE
for (j in 2:sqrt(i)) {
if (i %% j == 0) {
is_prime <- FALSE
break
}
}
if (is_prime) primes <- c(primes, i)
}
primes
}
find_primes(50)
# [1] 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
Exercise 3: Matrix Multiplication
Write nested for loops to multiply two 3x3 matrices (without using %*%).
Solution
A <- matrix(1:9, nrow = 3)
B <- matrix(9:1, nrow = 3)
C <- matrix(0, nrow = 3, ncol = 3)
for (i in 1:3) {
for (j in 1:3) {
for (k in 1:3) {
C[i, j] <- C[i, j] + A[i, k] * B[k, j]
}
}
}
C
# Verify
all.equal(C, A %*% B)
Key Takeaways
forloops iterate over sequences — useseq_along()for index-based iterationwhileloops continue while condition is TRUE — good for convergencerepeatloops run untilbreak— always ensure you have a break conditionbreakexits the loop,nextskips to the next iteration- Vectorized operations are faster — prefer
sapply(),apply(), or native vectorization - Pre-allocate results before filling in loops
lapply()returns a list,sapply()simplifies to vector
Next: Learn about R Functions — creating reusable code.