185 votes

L'opérateur ternaire existe-t-il dans R ?

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

2 votes

Vous voulez quelque chose de plus puissant que ifelse ou simplement une forme plus compacte ?

0 votes

@CarlWitthoft En général, une forme plus compacte ; simplement un moyen d'économiser l'écriture. if (x>1) y=2 else y=3 . Rédaction y= a un certain attrait.

324voto

kohske Points 30437

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

> 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 style c ?: :

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

ici, vous n'avez pas besoin de faire attention aux 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 parenthèses 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 de manière 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 crochets :

> 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

Ils ne sont pas destinés à un usage quotidien, mais peuvent être utiles pour apprendre certains éléments internes du langage R.

23voto

Richie Cotton Points 35365

Comme tout le monde l'a dit, utilisez ifelse mais vous pouvez définir des opérateurs de manière à obtenir une syntaxe proche de celle des opérateurs ternaires.

`%?%` <- 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 en fait si vous définissez les opérateurs sans l'option % des signes, donc 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 préséance de : est inférieur à ? .)

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

5voto

Tommy Points 16323

Juste pour faire une farce, vous peut redéfinir le ? pour fonctionner (presque) comme l'opérateur ternaire (C'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 préséance par défaut n'est pas comme en C.

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

rm(`?`)

4voto

Andrie Points 66979

Votre lien renvoie à un if déclaration.

> 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 le if en bâtonnets :

?`if`

La page d'aide de ifelse est à :

`?ifelse`

1 votes

Comme l'a dit @kohske, cela fonctionnera aussi : print(if (x<2) "Less than" else "Greater than")

4voto

Joshua Ulrich Points 68776

Il n'existe pas explicitement, mais vous pouvez le faire :

set.seed(21)
y <- 1:10
z <- rnorm(10)

condition1 <- TRUE
x1 <- if(condition1) y else z

o

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

La différence entre les deux est la suivante condition1 doit être un vecteur logique de longueur 1, alors que condition2 doit être un vecteur logique de la même longueur que x , y y z . La première renverra soit y o z (l'objet entier), alors que la seconde renverra 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 y z sont tous des vecteurs de longueur 1.

0 votes

Merci Joshua, votre réponse m'a beaucoup aidé, j'ai trouvé la réponse dans le message que vous avez mentionné. stackoverflow.com/a/8792474/3019570

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X