EthicsComputerCourses
Join training +91 90532 10052

if, else & Loops

R Programming · Lesson 12 of 29 Intermediate 7 min read Updated

So far your code has run from top to bottom, every line once. Control flow lets a program make decisions ("if the marks are 75 or more, print Distinction") and repeat work ("for each city, print the temperature"). R has the same tools as other languages: if, else, for, while and repeat.

In this lesson you will write conditions and loops, learn the errors R gives when a condition is a whole vector, and see when a vectorised function is the better choice.

if, else if and else

if runs a block of code only when its condition is TRUE. Add else if for more cases and else for "everything else". R checks the conditions from top to bottom and runs the first block that matches:

RTry it yourself
marks <- 72
if (marks >= 75) {
  grade <- "Distinction"
} else if (marks >= 60) {
  grade <- "First division"
} else if (marks >= 40) {
  grade <- "Pass"
} else {
  grade <- "Fail"
}
grade
Output
[1] "First division"

The condition goes in round brackets and the code in curly braces. 72 is not 75 or more, but it is 60 or more, so the second block runs and R skips the rest. Change marks to 35 or 90 and run it again.

One style rule matters in R: put else on the same line as the closing brace }. If else starts a new line at the top level of a script, R thinks the if has already finished and reports an "unexpected 'else'" error.

switch() for many fixed choices

When you compare one value against many fixed options, switch() is shorter than a chain of else if:

RTry it yourself
day <- "Sunday"
switch(day, Saturday = , Sunday = "Weekend", "Weekday")
day <- "Tuesday"
switch(day, Saturday = , Sunday = "Weekend", "Weekday")
temps <- c(31, 38)
if (temps > 35) print("Hot")
Output
[1] "Weekend"
[1] "Weekday"
Error in if (temps > 35) print("Hot") : the condition has length > 1
  • switch() looks for an argument whose name matches day and returns its value.
  • Saturday = , with nothing after the = "falls through" to the next value, so Saturday and Sunday share "Weekend".
  • The last, unnamed value is the default for everything else.

The last line shows a classic error. if needs one TRUE or FALSE, but temps > 35 gives two values. Since R 4.2.0 this is an error (older versions only warned and used the first value, hiding bugs). To act on each element, use the vectorised ifelse() from Vectorised Arithmetic. To ask about the whole vector, use any(temps > 35) or all(temps > 35).

for loops

A for loop runs its block once for each element of a vector:

RTry it yourself
cities <- c("Rohtak", "Jaipur", "Pune")
temps <- c(33, 36, 29)
for (i in seq_along(cities)) {
  cat(cities[i], "is", temps[i], "degrees\n")
}
total <- 0
for (t in temps) {
  total <- total + t
}
total
Output
Rohtak is 33 degrees
Jaipur is 36 degrees
Pune is 29 degrees
[1] 98
  • seq_along(cities) gives the positions 1, 2, 3, so i can index two vectors in step.
  • The second loop walks over the values directly: t is 33, then 36, then 29.
  • Values are not printed automatically inside a loop, so the first loop uses cat().

(The second loop only shows the pattern; in real code sum(temps) does the same job in one step.)

while, repeat, break and next

A while loop repeats as long as its condition stays TRUE. Use it when you do not know in advance how many steps you need. Priya has ₹10,000 saved and adds ₹1,500 each month; how many months until she reaches ₹15,000?

RTry it yourself
savings <- 10000
months <- 0
while (savings < 15000) {
  savings <- savings + 1500
  months <- months + 1
}
months
savings
for (n in 1:10) {
  if (n %% 2 == 0) next
  if (n > 7) break
  print(n)
}
Output
[1] 4
[1] 16000
[1] 1
[1] 3
[1] 5
[1] 7

After 4 months she has ₹16,000, the first amount that is not below the target. Make sure something inside a while loop changes the condition; otherwise the loop never ends (press Esc in your IDE to stop it).

The second loop shows two keywords that work in every kind of loop:

  • next skips the rest of this step and moves to the next one. Here it skips even numbers.
  • break leaves the loop completely. Here it stops once n passes 7.

R also has repeat { ... }, a loop with no condition that runs until a break. It is rare; a while loop is usually clearer.

Two loop habits that prevent bugs

RTry it yourself
x <- c()
for (i in 1:length(x)) print(i)
for (i in seq_along(x)) print(i)
squares <- numeric(5)
for (i in 1:5) squares[i] <- i^2
squares
Output
[1] 1
[1] 0
[1]  1  4  9 16 25

Use seq_along(x), not 1:length(x). When x is empty, length(x) is 0 and 1:0 counts down: 1, 0. The first loop runs twice when it should not run at all. seq_along(x) gives an empty sequence, so the second loop correctly does nothing.

Create the result vector first. numeric(5) makes a vector of five zeros, and the loop fills it in. Growing a vector one element at a time with c() inside a long loop is much slower, because R copies the whole vector at every step.

Common mistakes

  • Passing a vector to if. "the condition has length > 1" means you need ifelse(), any() or all().
  • Putting else on a new line at the top level of a script. Keep } else { together.
  • 1:length(x) on empty vectors. Use seq_along(x).
  • Infinite while loops. Make sure the loop changes the variable in its condition.
  • Writing a loop when a vectorised function exists. sum(), cumsum(), ifelse() and friends are shorter and faster.

Key points

  • if, else if and else choose which block runs; the condition must be a single TRUE or FALSE.
  • switch() picks a value from fixed named options, with an unnamed default.
  • for loops over a vector; use seq_along() for positions. while loops until its condition is FALSE.
  • next skips to the next step and break leaves the loop.
  • Pre-allocate results with numeric(n) and prefer vectorised code where possible.

Exercise

Write a loop that goes through these monthly electricity bills of a family in Kochi: 1450, 1720, 2980, 3310, 2650 and 1580 (in rupees). For each month print "Month 1: normal" if the bill is under ₹2,500 and "Month 1: high" otherwise. After the loop, print how many months were high. Then do the labelling again in one line with ifelse().

Show solution
R
bills <- c(1450, 1720, 2980, 3310, 2650, 1580)
high_count <- 0
for (i in seq_along(bills)) {
  if (bills[i] < 2500) {
    cat("Month", i, ": normal\n")
  } else {
    cat("Month", i, ": high\n")
    high_count <- high_count + 1
  }
}
high_count
ifelse(bills < 2500, "normal", "high")
Output
Month 1 : normal
Month 2 : normal
Month 3 : high
Month 4 : high
Month 5 : high
Month 6 : normal
[1] 3
[1] "normal" "normal" "high"   "high"   "high"   "normal"

The loop needs a counter and a cat() call, while ifelse() produces all six labels at once. cat() puts a space between its arguments, which is why there is a space before each colon; paste0() or sprintf() from Strings & Regular Expressions give you full control.

Quick Quiz

1. What happens with if (c(TRUE, FALSE)) print("yes") in R 4.6?

2. Which keyword skips to the next step of a loop?

3. Why is seq_along(x) safer than 1:length(x)?

4. In switch(x, a = , b = "AB", "other"), what is returned when x is "a"?

Learn R Programming with a mentor

Free lessons get you started. Our Data Science & Machine Learning training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call