использование оператора switch ()

106

Я немного смущен оператором switch в R. Просто поискав функцию в Google, я получаю следующий пример:

Обычно переключатель switch используется для перехода в соответствии со значением символа одного из аргументов функции.

 > centre <- function(x, type) {
 + switch(type,
 +        mean = mean(x),
 +        median = median(x),
 +        trimmed = mean(x, trim = .1))
 + }
 > x <- rcauchy(10)
 > centre(x, "mean")
 [1] 0.8760325
 > centre(x, "median")
 [1] 0.5360891
 > centre(x, "trimmed")
 [1] 0.6086504

Однако это похоже на то, что ifдля каждогоtype

Это все, что нужно switch()? Может кто-нибудь дать мне дополнительные примеры и лучшие приложения?

LostLin
источник
10
Да, вот и все.
Андри

Ответы:

119

Что ж, время снова приходит на помощь. Вроде switchвообще быстрее ifзаявлений. Так что и тот факт, что код короче / аккуратнее с switchутверждением, склоняется в пользу 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

Обновление Помня комментарий Джошуа, я попробовал другие способы тестирования. Микробенчмарк кажется лучшим. ... и он показывает похожие тайминги:

> 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

Заключительное обновление Здесь показано, насколько универсален switch:

switch(type, case1=1, case2=, case3=2.5, 99)

Это сопоставляет case2и case3с 2.5(безымянным) по умолчанию 99. Для получения дополнительной информации попробуйте?switch

Томми
источник
3
Использование такого цикла for может вызвать проблемы со сборкой мусора. Разница гораздо меньше , с более сопоставительной функцией: benchmark(test1('trimmed'), test2('trimmed'), replications=1e6).
Джошуа Ульрих
@JoshuaUlrich ... какую benchmarkфункцию вы используете? Кажется, не тот очевидный из «тестового» пакета?
Tommy
1
Согласно stackoverflow.com/questions/6262203/… «микробенчмарк» еще лучше.
Tommy
@JoshuaUlrich - я обновил ответ результатами из microbencmark, но они очень похожи на мои исходные. Я действительно не понимаю, как rbenchmark может решить проблему с GC, но, похоже, у него больше накладных расходов, вызывая evalи replicate.
Tommy
просто как в стороне, могу ли я иметь несколько случаев с одним и тем же выводом? ieswitch(type, c(this,that)=do something)
LostLin
4

Короче да . Но бывают случаи, когда вы можете отдать предпочтение одному против другого. Гугл "переключение регистра vs. если еще". По SO тоже уже ведутся дискуссии. Кроме того, вот хорошее видео, в котором говорится об этом в контексте MATLAB:

http://blogs.mathworks.com/pick/2008/01/02/matlab-basics-switch-case-vs-if-elseif/

Лично, когда у меня 3 или более чемодана, я обычно использую чехол / переключатель.

Джон Колби
источник