switch()
switch(EXPR, ...) The switch() function selects and evaluates one alternative from a list of arguments based on the value of EXPR. It handles two distinct modes: integer indexing and character string matching. This makes it useful for dispatching behavior based on a condition without writing lengthy if-else chains.
Syntax
switch(EXPR, ...)
The first argument, EXPR, is always evaluated as the selector. When EXPR is an integer, switch() returns the nth element in .... When EXPR is a character string, it matches the string exactly to named elements in ....
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
EXPR | integer or character | Required | The expression determining which alternative is selected. If named, the name must partially match EXPR. |
... | arguments | Required | The list of alternatives. Named elements are matched by character EXPR; an unnamed element is the default. |
Return value
The value of the selected element. Returns NULL invisibly when no element is selected (e.g., integer out of bounds or character with no match and no default).
Examples
Integer index mode
When EXPR evaluates to an integer, switch() returns the element at that position (1-indexed).
# First element
switch(1, "apple", "banana", "cherry")
# [1] "apple"
# Second element
switch(2, "apple", "banana", "cherry")
# [1] "banana"
# Third element
switch(3, "apple", "banana", "cherry")
# [1] "cherry"
# Out of bounds — returns NULL silently
switch(5, "apple", "banana", "cherry")
# [1] NULL
Character string mode
When EXPR is a character string, switch() matches it exactly to the names of the elements in .... Unlike integer mode where position alone determines the result, character mode searches for a named argument whose name matches EXPR without partial matching. This two-mode design lets you dispatch on user-facing labels like "mean" or "median" without maintaining a separate lookup table, keeping control flow local to the function body.
# Named matching
switch("red",
red = "apple",
green = "banana",
blue = "cherry"
)
# [1] "apple"
# No match — falls through to unnamed default
switch("purple",
red = "apple",
green = "banana",
blue = "cherry",
"unknown fruit"
)
# [1] "unknown fruit"
# No match and no default
switch("purple",
red = "apple",
green = "banana",
blue = "cherry"
)
# [1] NULL
Missing named element fallback
If a named element is missing, switch() evaluates the next non-missing element. This lets you create optional handlers with fallthrough behavior. The trailing-comma syntax after the name signals a deliberately absent value. When EXPR matches that entry, R skips forward and evaluates the following non-missing argument instead. This approach is useful for grouping multiple string inputs under a single handler without repeating identical logic, similar to fall-through cases in C-style switch statements.
switch("cc",
a = 1,
cc =, # missing — falls through
cd = 2, # this gets evaluated
d = 3
)
# [1] 2
Practical dispatch pattern
switch() is commonly used to dispatch behavior in functions based on a configuration argument. Each named alternative can be an expression, not just a simple value, so handlers can call other functions, perform computations, or even trigger errors for unrecognised inputs. The unnamed final argument with stop() catches invalid method names cleanly, turning an otherwise silent NULL return into an informative error message that points directly to the offending value.
calculate_stats <- function(data, method = "mean") {
switch(method,
mean = mean(data),
median = median(data),
sd = sd(data),
var = var(data),
stop("Unknown method: ", method)
)
}
calculate_stats(c(1, 2, 3, 4, 5), method = "median")
# [1] 3
calculate_stats(c(1, 2, 3, 4, 5), method = "sd")
# [1] 1.58114
Default value pattern
An unnamed argument at the end is the default when no named element matches the character EXPR. Without this fallback, a non-matching string produces a silent NULL that can propagate through your analysis undetected. The default can be any R expression, a static string, a computed value, or another function call. This pattern appears frequently in Shiny input handlers and API response formatters where you need to handle a fixed set of known cases plus an unknown catch-all.
get_status_message <- function(code) {
switch(code,
success = "Operation completed successfully.",
error = "An error occurred.",
warning = "Something looks off.",
"Unknown status code" # default
)
}
get_status_message("success")
# [1] "Operation completed successfully."
get_status_message("timeout")
# [1] "Unknown status code"
Edge cases
Invalid EXPR values
Integer 0 causes an error because switch() uses 1-based indexing matching R’s convention. NULL returns NULL immediately without evaluating any alternatives, which can mask bugs if a variable unexpectedly becomes NULL upstream. NA_character_ also returns NULL since NA cannot match any named element and has no default fallthrough. When writing functions that pass user input to switch(), validate that EXPR is neither zero, NULL, nor NA before the call to avoid silently wrong results.
# Zero is invalid
switch(0, "a", "b", "c")
# Error in switch(0, "a", "b", "c") :
# switching argument must be non-zero
# NULL input
switch(NULL, a = 1, b = 2)
# [1] NULL
# NA_character_ input
switch(NA_character_, a = 1, b = 2)
# [1] NULL
Multiple unnamed elements
More than one unnamed element causes an error since switch() cannot determine which to use as the default. The function expects exactly zero or one unnamed argument, any additional unnamed arguments trigger a runtime error with the message ‘more than one unnamed argument in switch.’ This constraint means you cannot have multiple fallback cases, if you need cascading defaults, handle them with nested switch() calls or an explicit if chain before the switch.
switch("x",
a = 1,
"default1",
"default2"
)
# Error in switch("x", a = 1, "default1", "default2") :
# more than one unnamed argument in switch
Multiple character matches
If two named elements partially match the same EXPR, the first match wins. R does not warn about ambiguous matches, so the ordering of named arguments matters when names share prefixes. This is different from pmatch() which can signal ambiguity. If your switch cases include both a short prefix and a longer variant, place the longer or more specific match first to ensure it gets checked before the shorter catch-all entry.
switch("cc",
c = "short c",
cc = "double c"
)
# [1] "short c"
Common mistakes
Assuming out-of-bounds returns a warning or error. When using integer mode with an index larger than the number of alternatives, switch() silently returns NULL with no warning. Always validate the index range if out-of-bounds behavior matters.
Using 1-indexed thinking in character mode. Character matching requires exact name matches, not partial index lookups. switch("1", "1" = "first") works but switch(1, "first") uses integer mode.
Forgetting the unnamed default for character EXPR. If you pass a character string that might not match any named element, add an unnamed argument at the end to serve as the default, otherwise you’ll get a silent NULL.