2011-10-19 7 views
92

Je suis un peu confus au sujet de l'instruction switch R. googler simplement la fonction que je reçois un exemple comme suit:commutateur() d'utilisation de l'instruction

Une utilisation courante de l'interrupteur est à la branche en fonction de la valeur de caractère l'un des arguments d'une fonction.

> 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 

Cependant, cela semble juste être la même chose que d'avoir simplement un tas de déclarations if désigné pour chaque type

Est-ce tout ce qu'il ya à switch()? Quelqu'un peut-il me donner d'autres exemples et de meilleures applications?

+7

Oui, c'est tout ce qu'il y a à faire. – Andrie

Répondre

95

Eh bien, chronométrer à la rescousse à nouveau. Il semble que switch est généralement plus rapide que if. Alors que, et le fait que le code est plus court/plus propre avec une déclaration switch se penche en faveur de 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 

Mise à jour avec le commentaire de Joshua à l'esprit, j'ai essayé d'autres moyens de référence. Le microbenchmark semble le meilleur. ... et montre les horaires similaires:

> 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 

mise à jour finale VOICI montrant comment polyvalent switch est:

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

Mappe case2 et case3 à 2.5 et la valeur par défaut (sans nom) à 99. Pour plus d'informations, essayez ?switch

+2

L'utilisation d'une boucle for comme celle-ci peut causer des problèmes avec le garbage collection. La différence est beaucoup plus faible avec une meilleure fonction de benchmarking: 'benchmark (test1 ('trimmed'), test2 ('trimmed'), réplications = 1e6)'. –

+0

@JoshuaUlrich ... quelle fonction 'benchmark' utilisez-vous? Pas la plus évidente du paquet "benchmark" semble-t-il? – Tommy

+1

Désolé, j'utilisais le paquetage rbenchmark. –

2

En résumé, oui. Mais il y a des moments où vous pourriez favoriser l'un contre l'autre. Google "case switch vs sinon". Il y a déjà des discussions sur le SO aussi. De plus, voici une bonne vidéo qui parle dans le contexte de Matlab:

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

Personnellement, quand j'ai 3 ou plus de cas, je généralement juste aller avec le cas/commutateur.