How to use the switch statement in R functions?
Well, switch
probably wasn't really meant to work like this, but you can:
AA = 'foo'
switch(AA,
foo={
# case 'foo' here...
print('foo')
},
bar={
# case 'bar' here...
print('bar')
},
{
print('default')
}
)
...each case is an expression - usually just a simple thing, but here I use a curly-block so that you can stuff whatever code you want in there...
switch() statement usage
Well, timing to the rescue again. It seems switch
is generally faster than if
statements.
So that, and the fact that the code is shorter/neater with a switch
statement leans in favor of switch
:
# Simplified to only measure the overhead of switch vs if
test1 <- function(type) {
switch(type,
mean = 1,
median = 2,
trimmed = 3)
}
test2 <- function(type) {
if (type == "mean") 1
else if (type == "median") 2
else if (type == "trimmed") 3
}
system.time( for(i in 1:1e6) test1('mean') ) # 0.89 secs
system.time( for(i in 1:1e6) test2('mean') ) # 1.13 secs
system.time( for(i in 1:1e6) test1('trimmed') ) # 0.89 secs
system.time( for(i in 1:1e6) test2('trimmed') ) # 2.28 secs
Update With Joshua's comment in mind, I tried other ways to benchmark. The microbenchmark seems the best. ...and it shows similar timings:
> library(microbenchmark)
> microbenchmark(test1('mean'), test2('mean'), times=1e6)
Unit: nanoseconds
expr min lq median uq max
1 test1("mean") 709 771 864 951 16122411
2 test2("mean") 1007 1073 1147 1223 8012202
> microbenchmark(test1('trimmed'), test2('trimmed'), times=1e6)
Unit: nanoseconds
expr min lq median uq max
1 test1("trimmed") 733 792 843 944 60440833
2 test2("trimmed") 2022 2133 2203 2309 60814430
Final Update Here's showing how versatile switch
is:
switch(type, case1=1, case2=, case3=2.5, 99)
This maps case2
and case3
to 2.5
and the (unnamed) default to 99
. For more information, try ?switch
Switch function in R: how to throw an error message or default value when the input isn't matched?
You can add a default like this.
animal_sound <- function(x) {
switch(x,
"dog" = "woof",
"cat" = "meow",
"bee" = "bzzz",
"duck" = "quack",
"default")
}
R's switch statement is not a special form, is it therefore slow?
If you look at internal code of switch
in file src/main/builtin.c, you can read in lines 1009-1025 :
This is a SPECIALSXP, so arguments need to be evaluated as needed.
SPECIALSXP
means :
no SEXPTYPE Description
7 SPECIALSXP special functions
So switch
is actually a special function which passes unevaluated arguments to the internal function.
Further reading the source code from line 1030 to line 1104 shows that as explained in ?switch
, the function either handles character
or number
in a simple and not fully optimized way.
This probably explains why switch
isn't particularly fast in situations which would for example require a binary search.
Use of switch() in R to replace vector values
The vectorised form of if
is ifelse
:
test <- ifelse(test == "He is", 1,
ifelse(test == "She is", 1,
ifelse(test == "He has", 2,
2)))
or
test <- ifelse(test %in% c("He is", "She is"), 1, 2)
switch
is basically a way of writing nested if
-else
tests. You should think of if
and switch
as control flow statements, not as data transformation operators. You use them to control the execution of an algorithm, eg to test for convergence or to choose which execution path to take. You wouldn't use them to directly manipulate data in most circumstances.
Switch statement throws error
The more obvious way to get what you want is with time + 12
.
It is simpler than switch
and allows you to pass a vector and not just a value.
But as your problem might be more complicated than the one you put in your example and if you feel you need to use switch (for which you can pass only one value at a time), and to complete my comment, you have 2 options to do that, as stated in the below sample from help(switch)
:
switch works in two distinct ways depending whether the first argument
evaluates to a character string or a number.If the value of EXPR is not a character string it is coerced to
integer. Note that this also happens for factors, with a warning, as
typically the character level is meant. If the integer is between 1
and nargs()-1 then the corresponding element of ... is evaluated and
the result returned: thus if the first argument is 3 then the fourth
argument is evaluated and returned.If EXPR evaluates to a character string then that string is matched
(exactly) to the names of the elements in .... If there is a match
then that element is evaluated unless it is missing, in which case the
next non-missing element is evaluated, so for example switch("cc", a =
1, cc =, cd =, d = 2) evaluates to 2. If there is more than one match,
the first matching element is used. In the case of no match, if there
is a unnamed element of ... its value is returned. (If there is more
than one such argument an error is returned.)
Either time is a character variable:
time <- "3"
switch(time, "1"=13, "2"=14, "3"=15, "4"=16)
# [1] 15
Or time is numeric:
time <- 3
switch(time, 13, 14, 15, 16)
# [1] 15
Related Topics
Non-Redundant Version of Expand.Grid
How to Determine If You Have an Internet Connection in R
Stop an R Program Without Error
Any Suggestions for How to Plot Mixem Type Data Using Ggplot2
Ggplot2: How to Use Same Colors in Different Plots for Same Factor
R Group by Date, and Summarize the Values
Tidyr How to Spread into Count of Occurrence
How to Manipulate the Strip Text of Facet_Grid Plots
Selecting Columns in R Data Frame Based on Those *Not* in a Vector
Take Sum of a Variable If Combination of Values in Two Other Columns Are Unique
Simple Approach to Assigning Clusters for New Data After K-Means Clustering
Rmarkdown: How to End Tabbed Content
How to Add a Factor Column to Dataframe Based on a Conditional Statement from Another Column
Call by Reference in R (Using Function to Modify an Object)
Count Observations Greater Than a Particular Value
Filling Missing Dates in a Grouped Time Series - a Tidyverse-Way