Control Flow in R
You are still tutoring that weekend R study group. The same five friends, Mara, Dev, Ada, Theo and Iris, sat a quiz out of 100 and scored 58, 91, 73, 49 and 84. In Lesson 1 you learned to read and write those scores by subsetting. Now you want your code to act on them: decide who passed, send a different message to each student, keep boosting scores until the class average is high enough, stop the moment you have lined up enough follow-ups.
Those are the three things control flow gives you: branch (do different work depending on a condition), loop (repeat work many times), and skip or stop partway through. The widget below is the whole idea in miniature, a loop that makes a yes/no decision each time around. Step through it.
By the end of this lesson you will be able to:
- Branch with
if,else ifandelse, and know when to reach forifelse()instead - Repeat work with a
forloop (a known set) and awhileloop (until a condition is met) - Skip one pass with
nextand stop a loop early withbreak
Prerequisites: you can build a vector, you know R's comparison operators like >= and == return TRUE/FALSE, and you can subset by name or condition.
if and else: a fork in the road
The most basic decision is a fork: if something is true, do this; otherwise, do that. In R you write it with if and else. The part in round brackets, the condition, must boil down to a single TRUE or FALSE, and the part in curly braces is the work to run.
First, build the scores once. Each lesson runs in a fresh R session, so we create the data right here (run this):
Here cat() simply prints its message to the console, and the \n at the end is a "newline" so the next message starts on a fresh line. R checked mara >= 60. That is FALSE (58 is below 60), so it skipped the if block and ran the else block. Change the score and the other branch runs.
When there are more than two outcomes, chain decisions with else if. R tries each condition top to bottom and runs the first block whose condition is TRUE, then stops checking:
if runs a block only when its condition is TRUE. else is the catch-all when it was FALSE. An else if chain checks conditions in order and takes the first match, so put the most specific condition first.When you have a whole vector: ifelse()
There is a trap waiting here. if wants one TRUE or FALSE. But scores >= 60 is a vector of five logicals, one per student. Hand that to if and R does not guess, it stops with an error:
if (scores >= 60) raises "the condition has length > 1" and halts. if is for a single decision, not a column of them. This is the single most common control-flow mistake beginners make.To make the same decision for every element at once, use ifelse(). You give it the test, the value to use where the test is TRUE, and the value to use where it is FALSE, and it returns a whole vector of results:
One label per student, in one line, no loop needed. Read the rule of thumb as: **if decides once; ifelse() decides element by element across a vector.**
Label every student at once
You have the whole scores vector and want a "pass" or "fail" label for every student in one go. Which line does that correctly?
ifelse() is vectorized: it applies the test to each element and returns one label per student.ifelse() is the direct, built-in tool.The for loop, one iteration at a time
A for loop runs the same block of code once for each item in a sequence. You write for (variable in sequence), and on each pass R sets variable to the next item and runs the body. Step through the widget below: watch the counter i change, see which branch the if takes, and the console build up line by line. That is exactly what a loop does, just sped up when you press Run.
Now point a loop at our study group. names(scores) gives the five names; the loop binds name to each one in turn and runs the body five times:
The sequence can be anything you can iterate: the values themselves (for (s in scores)), the names (above), or a count like 1:n when you just need to repeat something a fixed number of times:
ifelse(), sum() or mean() is shorter and faster, you will see much more of that in the iteration lesson later in this course.Count how many passed
Complete the loop so it adds 1 to passed for each student who scored 60 or more. Fill in the condition, then check. (You should get 3: Dev, Ada and Iris.)
Show answer
passed <- 0
for (s in scores) {
if (s >= 60) {
passed <- passed + 1
}
}
passed
#> [1] 3The while loop
A for loop runs a known number of times, once per item. But sometimes you do not know the count in advance, you just want to keep going until something becomes true. That is a while loop: it checks a condition, and as long as it is TRUE, it runs the body and checks again.
Say the group unlocks a reward when the class average reaches 75. Right now the average is 71. Each study session lifts everyone by 3 points. How many sessions until they get there? A while loop finds out by repeating until the average is high enough:
The flow is always the same four beats: check the condition, run the body, update something the condition depends on, and loop back. The widget shows that cycle:
while loop only ends when its condition becomes FALSE. If the body never changes what the condition depends on (here, avg), the loop runs forever, an infinite loop. Always make sure each pass moves you toward the exit.Which loop fits?
You want to keep simulating study sessions until the class average reaches 75, but you have no idea how many sessions that will take. Which loop is the right tool?
while is exactly the tool.while keeps going until the condition flips, however many passes that takes.next and break
Two small keywords give you fine control inside a loop. next skips the rest of the current pass and jumps straight to the next item. break stops the loop entirely. Both are almost always guarded by an if.
Suppose you are lining up follow-up sessions, but you can only fit two this week. Go through the students in order: skip anyone already passing (next), and once you have found two who need help, stop looking (break):
Trace it: Mara (58) fails, so she is logged. Dev and Ada pass, so next skips them. Theo (49) fails and is logged, which makes need_help reach 2, so break ends the loop before it ever reaches Iris.
next = "skip the rest of this pass." break = "leave the loop now." Reach for them when a condition mid-loop means there is no point finishing the current item, or no point continuing at all.Stop at the first struggler
Write a loop that walks the students in order, prints the first one who scored below 60, and then stops immediately (no point checking the rest). Fill in the keyword that leaves the loop, then check. (It should report Mara.)
Show answer
for (name in names(scores)) {
if (scores[name] < 60) {
cat("First struggling student:", name, "\n")
break
}
}
#> First struggling student: MaraReferences
A few authoritative, free places to take control flow further:
- Advanced R (2e): Control flow - the definitive treatment of
if,ifelse(),for,while,nextandbreak, including the length-1 condition rule. - An Introduction to R: Loops and conditional execution - the official manual on
ifand the loop constructs. - The R Language Definition: Control structures - the precise, formal rules for every conditional and loop keyword.
- Hands-On Programming with R: Loops - a gentle, beginner-first walk through
forandwhile.
Lesson 2 complete
Your code can now make decisions and repeat work. You branched with if, else if and else on a single TRUE/FALSE, and switched to ifelse() to label a whole vector at once; you repeated work with a for loop over a known set and a while loop that runs until a condition is met (watching out for infinite loops); and you steered loops from the inside with next to skip a pass and break to stop early.
Next, Lesson 3: Writing Functions in R. So far this logic lives loose in your script. A function lets you wrap a piece of it, give it a name, hand it inputs, and reuse it anywhere, the natural next step once your code starts branching and looping.