використання оператора switch ()


106

Я трохи розгублений щодо оператора переключення в Р. Просто гуглюючи функцію, я отримую такий приклад:

Загальним використанням перемикача є розгалуження відповідно до значення символу одного з аргументів функції.

 > 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()? Чи може хтось надати мені додаткові приклади та кращі програми?


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
Використання подібного циклу може спричинити проблеми зі збиранням сміття. Різниця набагато менше , з більш порівняльної функцією: benchmark(test1('trimmed'), test2('trimmed'), replications=1e6).
Джошуа Ульріх

@JoshuaUlrich ... яку benchmarkфункцію ви використовуєте? Чи не очевидний той із "бенчмаркового" пакету, як здається?
Томмі

1
Згідно stackoverflow.com/questions/6262203 / ... «microbenchmark» є ще краще.
Томмі

@JoshuaUlrich - я оновив відповідь результатами microbencmark, але вони дуже схожі на мої оригінальні. Я насправді не бачу, як rbenchmark обійдеться з проблемою GC, але, схоже, має більше накладних витрат на дзвінки evalта replicate.
Томмі

так само, як убік, чи можу я мати кілька випадків з однаковим результатом? тобтоswitch(type, c(this,that)=do something)
LostLin

4

Словом, так . Але бувають випадки, коли ви можете віддавати перевагу одному проти іншого. Google "перемикач справи проти іншого". Деякі дискусії вже є і в ТА. Також ось хороше відео, яке розповідає про це в контексті MATLAB:

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

Особисто, коли у мене є 3 і більше випадків, я зазвичай просто йду з справою / перемикачем.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.