Comme la question se pose, 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!
if (x>1) y=2 else y=3
. Ecrire y=
une fois a un certain attrait.
Comme la question se pose, 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!
if (x>1) y=2 else y=3
. Ecrire y=
une fois a un certain attrait.
Réponses:
De même que if
function in 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 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 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
Ce ne sont pas pour un usage quotidien, mais peut-être bon pour apprendre certains éléments internes du langage R.
Comme tout le monde l'a dit, utilisez ifelse
, mais vous pouvez définir des opérateurs de sorte que vous ayez presque la syntaxe d'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, 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 car la priorité de :
est inférieure à ?
.)
Malheureusement, cela rompt alors les opérateurs d'aide et de séquence existants.
Juste comme une farce, vous pouvez redéfinir l' ?
opérateur pour (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 en C.
N'oubliez pas de restaurer l'ancienne fonction d'aide lorsque vous avez terminé de jouer:
rm(`?`)
Je voudrais jeter un oeil à la ifelse
commande. Je l'appellerais encore mieux car il est également vectorisé. Un exemple utilisant le jeu de données cars:
> 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"
ifelse
avec votre exemple? ;)
Votre lien pointe vers une 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, cela 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 if
backticks:
?`if`
La page d'aide pour ifelse
est à:
`?ifelse`
print(if (x<2) "Less than" else "Greater than")
Cela 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
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, tandis que condition2
doit être un vecteur logique de la même longueur que x
, y
, et z
. Le premier retournera soit y
ou z
(l'objet entier), tandis que le second 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
et z
sont tous les vecteurs de longueur 1.
if
fonctionne comme un ifelse non visualisé s'il est utilisé de la manière suivante:
`if`(condition, doIfTrue, doIfFalse)
L'avantage d'utiliser ceci par rapport à ifelse est lorsque la vectorisation est gênante (c'est-à-dire que j'ai des choses scalaires booléennes et liste / vecteur en conséquence)
ifelse(TRUE, c(1,2), c(3,4))
[1] 1
`if`(TRUE, c(1,2), c(3,4))
[1] 1 2
ifelse
, ou simplement une forme plus compacte?