R Control Flow Exercises: 12 if/else, Loop & Function Practice Problems, Solved Step-by-Step
Twelve hands-on exercises on R's control flow: if/else, for loops, while, break, next, switch, and the short-circuit operators && and ||. Each problem is runnable in the page with an expandable worked solution.
Control flow in R is simpler than in most languages, and that simplicity hides two traps: if wants a single-value condition, and for loops are often the wrong tool when a vectorised operation would be shorter and faster. These exercises make both points concrete.
Section 1, if, else, and short-circuit operators
Exercise 1. A simple if/else
Write code that prints "pass" if a variable score is at least 60, otherwise "fail". Test it with score <- 72 and score <- 45.
Solution
In R, if is an expression, it returns a value. You can assign its result: grade <- if (score >= 60) "pass" else "fail".
Exercise 2. else if chain
Turn a numeric score into a letter grade: 90+ = A, 80-89 = B, 70-79 = C, 60-69 = D, below 60 = F. Write it with a chain of else if.
Solution
Order matters, we test from highest to lowest. Each branch is only reached when all previous conditions are false.
Exercise 3. && vs &
Predict what each of these returns, then run them:
Solution
Rule: use & and | for vectors, && and || only inside if statements on single values. Recent R versions enforce this by erroring when && sees vectors longer than one.
Exercise 4. ifelse() for vectors
Using x <- c(-3, -1, 0, 2, 5), return a vector of the same length where negatives become "neg", zero becomes "zero", and positives become "pos".
Solution
Nested ifelse() is the base R way to build more than two branches. For larger chains, switch to dplyr::case_when().
Section 2, for loops
Exercise 5. Sum of squares
Write a for loop that computes the sum of squares from 1 to n (inclusive). Test it with n <- 10. Then compute the same thing in one line without a loop.
Solution
The vectorised version is shorter, faster, and harder to get wrong. Reach for loops only when each iteration genuinely depends on the result of the previous one.
Exercise 6. Pre-allocate the result
Rewrite this slow loop:
To pre-allocate out to length 1000 first, then assign into out[i].
Solution
Growing a vector with c(out, x) re-copies the whole vector on every iteration, O(n²) behaviour that becomes painful at a few thousand iterations. Pre-allocation is O(n).
Exercise 7. Loop over a list
Given nums <- list(a = 1:5, b = 6:10, c = 11:20), use a for loop to print each element's name and its mean.
Solution
Looping over names() gives you both the name and a way to extract the element with nums[[nm]]. For a functional alternative, sapply(nums, mean) returns the same numbers.
Section 3, while, break, next
Exercise 8. while until convergence
Write a while loop that starts at x <- 1 and repeatedly replaces x with (x + 10/x) / 2 (Babylonian method for the square root of 10). Stop when the change is less than 1e-8. Report the final x and the number of iterations.
Solution
repeat { ... break } is the R equivalent of do ... while. A while loop would also work, but repeat/break is cleaner when the stop condition is easier to express mid-iteration.
Exercise 9. next, skip odd numbers
Write a for loop over 1:20 that prints only the even numbers, using next to skip the odd ones.
Solution
next is R's continue. It jumps to the top of the current loop for the next iteration, skipping the rest of the loop body.
Section 4, switch and functions
Exercise 10. switch for named branches
Write a function describe(season) that returns a short description:
"spring"→"mild""summer"→"hot""autumn"→"cool""winter"→"cold"- anything else →
"unknown"
Use switch(), not if/else.
Solution
The trailing unnamed argument is the default. switch() is typically faster and clearer than a long if/else chain when matching a single string against a fixed set of values.
Exercise 11. Combine if/else and a for loop
Write a function count_negative(x) that takes a numeric vector and returns the count of strictly negative elements, using an explicit for loop with an if inside. Then compare to the vectorised sum(x < 0).
Solution
Both give the same answer. The vectorised version is significantly faster on large vectors and is the idiomatic R style. The loop version is worth writing once so you are comfortable with the alternative.
Exercise 12. Early return from a function
Write first_negative(x) that returns the first strictly negative element of a numeric vector, or NA if there are none. Use return() to exit as soon as you find one.
Solution
return() exits the function early. This is one of the few cases where a loop is genuinely simpler than the vectorised alternative, until you remember x[x < 0][1].
Summary
ifreturns a value and can be assigned. Useelse iffor more than two branches.&&/||are for single-value logic insideif;&/|are for element-wise vector logic.ifelse()anddplyr::case_when()are the vectorised alternatives to nestedif/else.forloops: pre-allocate the result, loop overseq_len(n)ornames(x), reach for vectorised alternatives first.whileandrepeat { break }handle convergence loops.nextskips to the next iteration.switch()is clearer than longif/elsechains when matching one value against many named cases.