IF, ELSE, ELSE IF Statement in R
โก Smart Summary
If Else and Else If statements in R choose which block of code runs based on a logical condition. This walkthrough covers the two-branch form, multi-branch chains, the vectorized ifelse() function, and switch() for exact matches.

The if else Statement in R
An if else statement runs one block of code when a condition is TRUE and another when it is FALSE. In R the syntax is:
if (condition) { Expr1 } else { Expr2 }
Check whether a variable named quantity is above 20. If it is, the code prints “You sold a lot!”, otherwise it prints “Not enough for today”.
# Create vector quantity quantity <- 25 # Set the if-else statement if (quantity > 20) { print('You sold a lot!') } else { print('Not enough for today') }
Output:
## [1] "You sold a lot!"
Note: indentation does not change how R runs the code, but consistent indentation is what keeps a long chain of conditions readable. Note also that the closing brace and the else keyword must sit on the same line, otherwise R treats the if block as complete and throws an error.
The else if Statement in R
Chain further tests with else if. R has no elif keyword, that is Python; in R you write the two words separately, and you can add as many branches as you need. The syntax is:
if (condition1) { expr1 } else if (condition2) { expr2 } else if (condition3) { expr3 } else { expr4 }
Suppose you want three outcomes: below 20 prints “Not enough for today”, between 20 and 30 prints “Average day”, and above 30 prints “What a great day!”.
You can try to change the amount of quantity.
# Create the variable quantity quantity <- 10 # Create multiple condition statement if (quantity < 20) { print('Not enough for today') } else if (quantity >= 20 & quantity <= 30) { print('Average day') } else { print('What a great day!') }
Output:
## [1] "Not enough for today"
Example 2:
VAT rates differ by product category. Imagine three categories, each with its own rate:
| Categories | Products | VAT |
|---|---|---|
| A | Book, magazine, newspaper, etc.. | 8% |
| B | Vegetable, meat, beverage, etc.. | 10% |
| C | Tee-shirt, jean, pant, etc.. | 20% |
An else if chain applies the correct rate to whatever the customer bought:
category <- 'A' price <- 10 if (category =='A'){ cat('A vat rate of 8% is applied.','The total price is',price *1.08) } else if (category =='B'){ cat('A vat rate of 10% is applied.','The total price is',price *1.10) } else { cat('A vat rate of 20% is applied.','The total price is',price *1.20) }
Output:
## A vat rate of 8% is applied. The total price is 10.8
The ifelse() Vectorized Function in R
The if statement handles exactly one value. Give it a vector and R 4.2 or later raises an error, because the condition must be a single TRUE or FALSE. ifelse() solves this by testing every element at once and returning a vector of the same length.
quantities <- c(10, 25, 40, 18) # if cannot do this result <- ifelse(quantities > 20, 'You sold a lot!', 'Not enough for today') result
Output:
## [1] "Not enough for today" "You sold a lot!" "You sold a lot!" ## [4] "Not enough for today"
The three arguments are the test, the value returned where the test is TRUE, and the value returned where it is FALSE. All three are recycled to the same length.
Nesting ifelse() reproduces an else if chain across a whole vector:
ifelse(quantities < 20, 'Not enough for today', ifelse(quantities <= 30, 'Average day', 'What a great day!'))
Two limits are worth knowing. ifelse() drops attributes such as factor levels and Date class from the result, and it evaluates both branches for every element, so it is wasteful when one branch is expensive. The dplyr alternative case_when() avoids the nesting entirely and keeps types intact:
library(dplyr) case_when( quantities < 20 ~ 'Not enough for today', quantities <= 30 ~ 'Average day', TRUE ~ 'What a great day!' )
The switch() Statement in R
When every branch tests the same variable for equality, a long else if chain becomes hard to read. switch() replaces it with a single lookup.
category <- 'A' price <- 10 vat <- switch(category, 'A' = 1.08, 'B' = 1.10, 'C' = 1.20, 1.20) # the unnamed last value is the default cat('The total price is', price * vat)
Three rules govern its behaviour:
- With a character argument, switch() matches the name exactly. There is no partial matching and no pattern matching.
- An unnamed final element acts as the default. Without one, an unmatched value returns NULL invisibly, which is a common source of silent bugs.
- With an integer argument, switch() selects by position instead: switch(2, “a”, “b”, “c”) returns “b”.
Use switch() for exact matches against a fixed set of values, and keep else if for ranges and compound conditions, which switch() cannot express. To apply a condition repeatedly over a sequence, combine it with a for loop or a while loop.
Logical Operators in R Conditions
The operators that build a condition behave differently from one another, and the difference matters.
| Operator | Meaning | Use it in |
|---|---|---|
| & | Element-wise AND | ifelse(), filter(), whole vectors |
| && | Single-value AND, short-circuits | if () and while () |
| | | Element-wise OR | ifelse(), filter(), whole vectors |
| || | Single-value OR, short-circuits | if () and while () |
| ! | NOT, negates the test | Anywhere |
| %in% | Is the value in this set? | Replaces long OR chains |
Why short-circuiting matters. The double form stops as soon as the answer is settled, so the right-hand side is never evaluated when the left already decides the outcome. That makes it safe to write a guard clause:
# Safe: length() is checked before x[1] is touched if (length(x) > 0 && x[1] > 10) print('ok')
Comparing against several values. Reach for %in% rather than chaining equality tests, which is both shorter and harder to mistype:
if (category %in% c('A', 'B')) { print('Reduced VAT rate applies') }
One final warning: a single equals sign assigns a value, it does not compare. Always write == inside a condition.
Conditional Statements in R: Quick Reference
Every construct used in this tutorial is listed below:
| Objective | Code |
|---|---|
| Two branches |
if (cond) { a } else { b } |
| Multiple branches |
if (c1) { a } else if (c2) { b } else { c } |
| Vectorized condition |
ifelse(test, yes, no)
|
| Multi-branch on a vector |
case_when(c1 ~ a, c2 ~ b, TRUE ~ c)
|
| Exact match lookup |
switch(x, "A" = 1, "B" = 2, 0) |
| Membership test |
if (x %in% c("A", "B")) { } |

