Como a pergunta é, existe uma sequência de controle em R semelhante ao operador ternário de C ? Se sim, como você o usa? Obrigado!
if (x>1) y=2 else y=3. Escrever y=uma vez tem um certo apelo.
Como a pergunta é, existe uma sequência de controle em R semelhante ao operador ternário de C ? Se sim, como você o usa? Obrigado!
if (x>1) y=2 else y=3. Escrever y=uma vez tem um certo apelo.
Respostas:
Como ifis function in Re retorna a avaliação mais recente, if-else é equivalente a ?:.
> a <- 1
> x <- if(a==1) 1 else 2
> x
[1] 1
> x <- if(a==2) 1 else 2
> x
[1] 2
O poder de R é a vetorização. A vetorização do operador ternário é 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
Brincadeirinha, você pode definir o estilo c ?::
`?` <- function(x, y)
eval(
sapply(
strsplit(
deparse(substitute(y)),
":"
),
function(e) parse(text = e)
)[[2 - as.logical(x)]])
aqui, você não precisa se preocupar com colchetes:
> 1 ? 2*3 : 4
[1] 6
> 0 ? 2*3 : 4
[1] 4
> TRUE ? x*2 : 0
[1] 2
> FALSE ? x*2 : 0
[1] 0
mas você precisa de colchetes para atribuição :(
> y <- 1 ? 2*3 : 4
[1] 6
> y
[1] 1
> y <- (1 ? 2*3 : 4)
> y
[1] 6
Finalmente, você pode fazer uma maneira muito semelhante com 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
}
}
Você pode se livrar de colchetes:
> 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
Estes não são para uso diário, mas talvez sejam bons para aprender alguns internos da língua R.
Como todo mundo disse, use ifelse, mas você pode definir operadores para ter quase a sintaxe do operador ternário.
`%?%` <- 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
Na verdade, funciona se você definir os operadores sem os %sinais, para que você possa ter
`?` <- 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"
(Isso funciona porque a precedência de :é menor que ?.)
Infelizmente, isso interrompe a ajuda existente e os operadores de sequência.
Assim como uma brincadeira, você pode redefinir o ?operador para (quase) funcionar como o operador ternário (ESTA É UMA IDÉIA RUIM):
`?` <- 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")
... Mas você precisa colocar as expressões entre parênteses, porque a precedência padrão não é como em C.
Lembre-se de restaurar a função de ajuda antiga quando terminar de jogar:
rm(`?`)
Eu daria uma olhada no ifelsecomando. Eu o chamaria ainda melhor porque também é vetorizado. Um exemplo usando o conjunto de dados de carros:
> 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"
ifelsecom o seu exemplo? ;)
Seu link aponta para uma ifdeclaração.
> x <- 1
> if(x < 2) print("Less than") else print("Greater than")
[1] "Less than"
Se sua variável de entrada for um vetor, ifelsepoderá ser mais adequado:
> x <- 1:3
> ifelse(x<=2, "Less than or equal", "Greater than")
[1] "Less than or equal" "Less than or equal" "Greater than"
Para acessar a página de ajuda if, é necessário incorporar os ifbackticks:
?`if`
A página de ajuda para ifelseestá em:
`?ifelse`
print(if (x<2) "Less than" else "Greater than")
Não existe explicitamente, mas você pode:
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)
A diferença entre os dois é que condition1deve ser um vector de comprimento lógico 1, ao passo que condition2deve ser um vector lógico do mesmo comprimento que x, ye z. O primeiro retornará um you z(o objeto inteiro), enquanto o segundo retornará o elemento correspondente de y( condition2==TRUE) ou z( condition2==FALSE).
Também nota que ifelseserá mais lenta do que if/ elsese condition, ye zsão todos os vectores com um comprimento.
if funciona como ifelse não-vetorizado se usado da seguinte maneira:
`if`(condition, doIfTrue, doIfFalse)
A vantagem de usar isso sobre ifelse é quando a vetorização está no caminho (ou seja, eu tenho como resultado booleano escalar e coisas de lista / vetor)
ifelse(TRUE, c(1,2), c(3,4))
[1] 1
`if`(TRUE, c(1,2), c(3,4))
[1] 1 2
ifelse, ou apenas uma forma mais compacta?