Est-ce que l’opérateur ternaire existe dans R?

Comme le demande la question, y a-t-il une séquence de contrôle dans R similaire à l’ opérateur ternaire de C? Si oui, comment l’utilisez vous? Merci!

Comme if est fonction dans R et renvoie la dernière évaluation, if-else équivaut à ?: .

 > a < - 1 > x < - if(a==1) 1 else 2 > x [1] 1 > x < - if(a==2) 1 else 2 > x [1] 2 

La puissance de R est la vectorisation. La vectorisation de l’opérateur ternaire est ifelse :

 > a < - c(1, 2, 1) > x < - ifelse(a==1, 1, 2) > x [1] 1 2 1 > x < - ifelse(a==2, 1, 2) > x [1] 2 1 2 

Je plaisante, vous pouvez définir le c-style ?: ::

 `?` < - function(x, y)  eval(   sapply(    strsplit(     deparse(substitute(y)),     ":"   ),   function(e) parse(text = e)  )[[2 - as.logical(x)]]) 

ici, vous n'avez pas à vous soucier des parenthèses:

 > 1 ? 2*3 : 4 [1] 6 > 0 ? 2*3 : 4 [1] 4 > TRUE ? x*2 : 0 [1] 2 > FALSE ? x*2 : 0 [1] 0 

mais vous avez besoin de crochets pour l'affectation 🙁

 > y < - 1 ? 2*3 : 4 [1] 6 > y [1] 1 > y < - (1 ? 2*3 : 4) > y [1] 6 

Enfin, vous pouvez faire très similaire avec c:

 `?` < - function(x, y) { xs <- as.list(substitute(x)) if (xs[[1]] == as.name("<-")) x <- eval(xs[[3]]) r <- eval(sapply(strsplit(deparse(substitute(y)), ":"), function(e) parse(text = e))[[2 - as.logical(x)]]) if (xs[[1]] == as.name("<-")) { xs[[3]] <- r eval.parent(as.call(xs)) } else { r } } 

Vous pouvez vous débarrasser des parenthèses:

 > y < - 1 ? 2*3 : 4 > y [1] 6 > y < - 0 ? 2*3 : 4 > y [1] 4 > 1 ? 2*3 : 4 [1] 6 > 0 ? 2*3 : 4 [1] 4 

Ce ne sont pas pour un usage quotidien, mais peut-être bon pour apprendre certains internes du langage R.

Comme tout le monde l’a dit, utilisez ifelse , mais vous pouvez définir des opérateurs pour avoir la syntaxe de l’opérateur ternaire.

 `%?%` < - function(x, y) list(x = x, y = y) `%:%` <- function(xy, z) if(xy$x) xy$y else z TRUE %?% rnorm(5) %:% month.abb ## [1] 0.05363141 -0.42434567 -0.20000319 1.31049766 -0.31761248 FALSE %?% rnorm(5) %:% month.abb ## [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec" # or, more generally condition %?% value1 %:% value2 

Cela fonctionne réellement si vous définissez les opérateurs sans les signes % , de sorte que vous pourriez avoir

 `?` < - function(x, y) if(x) y[[1]] else y[[2]] `:` <- function(y, z) list(y, z) TRUE ? rnorm(5) : month.abb ## [1] 1.4584104143 0.0007500051 -0.7629123322 0.2433415442 0.0052823403 FALSE ? rnorm(5) : month.abb ## [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec" 

(Cela fonctionne parce que la priorité de : est inférieure à ? )

Malheureusement, cela brise alors les opérateurs d'aide et de séquence existants.

Juste comme une farce, vous pouvez redéfinir le ? opérateur à (presque) travailler comme l’opérateur ternaire (CECI EST UNE MAUVAISE IDÉE):

 `?` < - function(x, y) { y <-substitute(y); if(x) eval(y[[2]], parent.frame()) else eval(y[[3]], parent.frame()) } x <- 1:3 length(x) ? (x*2) : 0 x <- numeric(0) length(x) ? (x*2) : 0 for(i in 1:5) cat(i, (i %% 2) ? "Odd\n" : "Even\n") 

... Mais vous devez mettre les expressions entre parenthèses car la priorité par défaut n'est pas comme dans C.

N'oubliez pas de restaurer l'ancienne fonction d'aide lorsque vous avez fini de jouer:

 rm(`?`) 

Votre lien pointe vers une déclaration if .

 > x < - 1 > if(x < 2) print("Less than") else print("Greater than") [1] "Less than" 

Si votre variable d'entrée est un vecteur, alors ifelse pourrait être plus approprié:

 > x < - 1:3 > ifelse(x< =2, "Less than or equal", "Greater than") [1] "Less than or equal" "Less than or equal" "Greater than" 

Pour accéder à la page d'aide de if , vous devez intégrer les ift backticks:

 ?`if` 

La page d'aide pour ifelse est à:

 `?ifelse` 

Il n’existe pas explicitement, mais vous pouvez faire:

 set.seed(21) y < - 1:10 z <- rnorm(10) condition1 <- TRUE x1 <- if(condition1) y else z 

ou

 condition2 < - sample(c(TRUE,FALSE),10,TRUE) x2 <- ifelse(condition2, y, z) 

La différence entre les deux est que condition1 doit être un vecteur logique de longueur 1, alors que condition2 doit être un vecteur logique de même longueur que x , y et z . Le premier retournera soit y ou z (l'object entier), tandis que le second retournera l'élément correspondant de y ( condition2==TRUE ) ou z ( condition2==FALSE ).

Notez également que ifelse sera plus lent que if / else si condition , y et z sont tous des vecteurs de longueur 1.

Je regarderais la commande ifelse . Je l’appellerais encore mieux car il est également vectorisé. Un exemple d’utilisation du jeu de données de voitures:

 > cars$speed > 20 [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [25] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [37] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE [49] TRUE TRUE > ifelse(cars$speed > 20, 'fast', 'slow') [1] "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" [11] "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" [21] "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" [31] "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" "slow" [41] "slow" "slow" "slow" "fast" "fast" "fast" "fast" "fast" "fast" "fast" 

if fonctionne comme sivse non utilisé si utilisé de la manière suivante:

 `if`(condition, doIfTrue, doIfFalse) 

L’avantage d’utiliser ceci sur ifelse est lorsque la vectorisation est dans le chemin (c’est-à-dire que j’ai un booléen scalaire et des choses list / vector en résultat)

 ifelse(TRUE, c(1,2), c(3,4)) [1] 1 `if`(TRUE, c(1,2), c(3,4)) [1] 1 2