Control Flow
Reviewed & published by Brayan K
Control flow is how R decides what to run and how often — branching with if/else and repeating with for and while loops, so your program can react to data instead of running straight through.
Part of the free R course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
By the end of this lesson you'll branch with if/else if/else, transform vectors with ifelse(), repeat work with for and while loops, and steer loops with break and next.
What You'll Learn in This Lesson
- How to branch with if, else if, and else
- When to use the vectorized ifelse() instead
- How to repeat code with a for loop
- How to loop safely with seq_along()
- How a while loop runs until its condition is FALSE
- How break and next control loop execution
1️⃣ Branching with if / else
An if statement runs a block only when its condition is TRUE; else if and else add fallbacks. For deciding values across a whole vector, use the vectorized ifelse() instead.
# if / else if / else makes decisions based on a TRUE/FALSE condition.
temp <- 30
if (temp > 28) {
print("It's hot")
} else if (temp > 15) {
print("Pleasant")
} else {
print("Cold")
} # -> [1] "It's hot"
# ifelse() is the VECTORIZED version — it picks per element:
scores <- c(45, 80, 60, 95)
ifelse(scores >= 60, "pass", "fail") # -> [1] "fail" "pass" "pass" "pass"2️⃣ Repeating with for Loops
A for loop runs its body once for each element of a vector. You can loop over indices (1:3) or over the items themselves. seq_along() gives safe indices that won't break on empty vectors.
# A for loop repeats code for each element of a vector.
for (i in 1:3) {
cat("Step", i, "\n")
}
# Loop over the items themselves, not just indices:
fruits <- c("apple", "pear", "plum")
for (fruit in fruits) {
cat("I like", fruit, "\n")
}
# Build up a result with seq_along() for safe indexing:
total <- 0
nums <- c(5, 10, 15)
for (i in seq_along(nums)) {
total <- total + nums[i]
}
cat("Total:", total, "\n") # -> Total: 303️⃣ while Loops, break, and next
A while loop repeats as long as its condition holds — make sure something inside changes the condition, or it never stops. break exits a loop early; next skips to the next iteration.
# A while loop repeats AS LONG AS its condition stays TRUE.
countdown <- 3
while (countdown > 0) {
cat(countdown, "...\n")
countdown <- countdown - 1 # MUST change, or it loops forever
}
cat("Lift off!\n")
# break exits a loop early; next skips to the next iteration:
for (i in 1:6) {
if (i == 4) break # stop entirely at 4
if (i %% 2 == 0) next # skip even numbers
cat("odd:", i, "\n")
}Your turn. Fill in the ___ blank, run it, and compare with the expected output.
# 🎯 YOUR TURN — replace each ___ then run it.
# 1) Loop over the numbers 1 to 5
for (i in 1:5) {
if (i %% 2 == ___) cat(i, "is even\n") else cat(i, "is odd\n") # 👉 replace ___ with 0
}
# ✅ Expected output:
# 1 is odd
# 2 is even
# 3 is odd
# 4 is even
# 5 is oddMini-Challenge: FizzBuzz
The classic interview warm-up. Write it from the outline, run it, and check it against the example output. It exercises loops, %%, and nested conditions.
# 🎯 MINI-CHALLENGE: FizzBuzz (a classic).
#
# Loop from 1 to 15. For each number:
# - print "FizzBuzz" if divisible by BOTH 3 and 5
# - else print "Fizz" if divisible by 3
# - else print "Buzz" if divisible by 5
# - else print the number itself
# (hint: use %% and if / else if / else)
#
# ✅ Example output (first lines):
# 1
# 2
# Fizz
# 4
# Buzz
# ...
# your code hereCommon Errors (and the fix)
- "the condition has length > 1" — you gave if a whole vector. if needs ONE value; use ifelse() for vectors.
- Infinite while loop — you forgot to update the variable the condition checks. Ensure each pass moves toward the exit; press Esc to stop a runaway loop.
- Looping 1:length(x) on empty x — that becomes 1:0 and loops twice. Use seq_along(x) instead.
- Growing a vector in a loop — appending each pass is slow. Pre-allocate with numeric(n) or, better, vectorize.
Pro Tips
- 💡 Prefer vectorized code: many loops can be replaced by one vectorized line or an apply call (next track).
- 💡 Use seq_along(): it's the loop-safe way to iterate over positions.
- 💡 Keep conditions simple: compute a TRUE/FALSE into a named variable first if the if gets long.
📋 Quick Reference — Control Flow
| Task | R Syntax |
|---|---|
| Branch | if (cond) { } else { } |
| Vectorized choice | ifelse(cond, a, b) |
| For loop | for (i in 1:n) { } |
| Safe indices | seq_along(x) |
| While loop | while (cond) { } |
| Exit / skip | break ; next |
🎉 Lesson Complete!
- ✅ if / else if / else branches on a single condition
- ✅ ifelse() chooses per element across a vector
- ✅ for loops repeat over each element
- ✅ seq_along() gives safe loop indices
- ✅ while, break, and next give fine control
Practice quiz
How many values must the condition in an if statement evaluate to?
- A whole vector of conditions
- At least two
- Exactly one (a single TRUE or FALSE)
- Zero
Answer: Exactly one (a single TRUE or FALSE). if needs a single logical value; a length>1 vector causes an error.
What does ifelse(c(45, 80) >= 60, "pass", "fail") return?
- c("fail", "pass")
- c("pass", "fail")
- A single value "fail"
- An error
Answer: c("fail", "pass"). ifelse() works element by element: 45 fails, 80 passes.
Which loop runs its body once for each element of a vector?
- repeat-until
- do-while
- switch
- for
Answer: for. for (x in v) iterates over each element of v.
Why prefer seq_along(x) over 1:length(x) in a loop?
- seq_along is shorter to type only
- 1:length(x) misbehaves when x is empty (becomes 1:0)
- 1:length(x) is a syntax error
- seq_along runs in parallel
Answer: 1:length(x) misbehaves when x is empty (becomes 1:0). For empty x, 1:length(x) is 1:0 and iterates twice; seq_along gives nothing.
A while loop keeps running as long as its condition is...
- TRUE
- FALSE
- NA
- numeric
Answer: TRUE. while repeats while the condition stays TRUE.
What does break do inside a loop?
- Skips to the next iteration
- Restarts the loop
- Exits the entire loop immediately
- Pauses for one second
Answer: Exits the entire loop immediately. break leaves the loop entirely; next skips to the next iteration.
What does next do inside a loop?
- Exits the loop completely
- Skips the rest of the current iteration
- Doubles the counter
- Prints the index
Answer: Skips the rest of the current iteration. next jumps straight to the next iteration without finishing the body.
What does the expression 7 %% 3 evaluate to?
- 2
- 3
- 0
- 1
Answer: 1. %% is the modulo operator; 7 divided by 3 leaves remainder 1.
A common cause of an infinite while loop is...
- Using break too early
- Forgetting to update the variable the condition checks
- Looping over a vector
- Calling cat() inside it
Answer: Forgetting to update the variable the condition checks. If nothing makes the condition FALSE, the loop never ends.
Which is the VECTORIZED way to choose values per element?
- if (cond) a else b
- for with break
- ifelse(cond, a, b)
- while (cond)
Answer: ifelse(cond, a, b). ifelse() is vectorized; if handles a single condition for control flow.
Continue this course
- Previous: Functions
- Next: Lists — Hold mixed types and nested data in R's flexible list structure
- Quick reference: R cheat sheet
Frequently asked questions
What is the difference between if and ifelse() in R?
if is a control structure that evaluates ONE condition (a single TRUE/FALSE) and runs one block or another — use it for program logic. ifelse() is a vectorized function that takes a whole vector of conditions and returns a vector, choosing the 'yes' or 'no' value element by element. For deciding which branch of code to run, use if; for transforming a column of data based on a condition, use ifelse().
Should I use loops in R, or is there a better way?
Loops are perfectly valid and sometimes the clearest choice, especially for tasks with side effects or genuine step-by-step logic. But for transforming data, R's vectorized operations and the apply family (covered later) are usually faster and more idiomatic. A good rule: reach for vectorized code first; use a loop when the logic is inherently sequential or easier to read as a loop. Don't fear loops — just don't use them where one vectorized line would do.
What do break and next do?
break immediately exits the entire loop, skipping any remaining iterations — useful when you've found what you were looking for. next skips the rest of the current iteration and jumps to the next one — useful to ignore certain cases without nesting your code in a big if. Both work in for and while loops and help keep loop bodies readable.
Why is my while loop running forever?
A while loop keeps going as long as its condition is TRUE, so something inside the loop must eventually make the condition FALSE. The classic bug is forgetting to update the variable the condition checks — for example counting down but never subtracting. Always make sure each iteration moves you closer to the exit condition. If a loop hangs, press Esc (or Ctrl+C) to stop it, then fix the update step.