如问题所问,R中是否存在类似于C的三元运算符的控制序列?如果有,你如何使用它?谢谢!
我会看一下ifelse命令。我认为它更好,因为它也是向量化的。一个使用cars数据集的例子:
ifelse
> 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语句。
if
> x <- 1 > if(x < 2) print("Less than") else print("Greater than") [1] "Less than"
如果你的输入变量是一个向量,那么ifelse可能更适合:
> x <- 1:3 > ifelse(x<=2, "Less than or equal", "Greater than") [1] "Less than or equal" "Less than or equal" "Greater than"
要访问if的帮助页面,你需要在反引号中嵌入if:
?`if`
ifelse的帮助页面在:
`?ifelse`
由于if是R中的函数,返回最新的求值,if-else等价于?:。
R
?:
> a <- 1 > x <- if(a==1) 1 else 2 > x [1] 1 > x <- if(a==2) 1 else 2 > x [1] 2
R的幂是向量化。三元运算符的向量化是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
开个玩笑,你可以定义c-style ?::
`?` <- function(x, y) eval( sapply( strsplit( deparse(substitute(y)), ":" ), function(e) parse(text = e) )[[2 - as.logical(x)]])
在这里,你不需要考虑括号:
> 1 ? 2*3 : 4 [1] 6 > 0 ? 2*3 : 4 [1] 4 > TRUE ? x*2 : 0 [1] 2 > FALSE ? x*2 : 0 [1] 0
但你需要括号赋值:(
> y <- 1 ? 2*3 : 4 [1] 6 > y [1] 1 > y <- (1 ? 2*3 : 4) > y [1] 6
最后,你可以用类似的方法来处理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 } }
你可以去掉括号:
> 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
这些不是日常使用的,但可能有助于学习R语言的一些内部知识。
它并不明确存在,但你可以这样做:
set.seed(21) y <- 1:10 z <- rnorm(10) condition1 <- TRUE x1 <- if(condition1) y else z
或
condition2 <- sample(c(TRUE,FALSE),10,TRUE) x2 <- ifelse(condition2, y, z)
两者的区别在于condition1必须是长度为1的逻辑向量,而condition2必须是与x、y和z长度相同的逻辑向量。第一个将返回y或z(整个对象),而第二个将返回y (condition2==TRUE)或z (condition20)的相应元素。
condition1
condition2
x
y
z
condition2==TRUE
还要注意,如果condition、y和z都是长度为1的向量,那么ifelse将比if / else慢。
condition
else
就像其他人说的,使用ifelse,但是你可以定义操作符,这样你就几乎有了三元操作符语法。
`%?%` <- 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
如果你定义的操作符没有%符号,它实际上是有效的,所以你可以
%
`?` <- 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"
(这是因为:的优先级比?低。)
:
?
不幸的是,这将破坏现有的帮助和序列操作符。
就像一个恶作剧,你可以重新定义?操作符(几乎)像三元操作符一样工作(这是一个坏主意):
`?` <- 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")
... 但是你需要把表达式放在括号里因为默认的优先级和C语言不同。
只要记得在游戏结束后恢复旧的帮助功能:
rm(`?`)
if工作类似于unvectorised ifelse,如果以以下方式使用:
`if`(condition, doIfTrue, doIfFalse)
使用这个优于ifelse的优势是当向量化是在路上(即我有标量布尔和列表/向量的东西作为结果)
ifelse(TRUE, c(1,2), c(3,4)) [1] 1 `if`(TRUE, c(1,2), c(3,4)) [1] 1 2
我写了一个小的语言扩展,它在r中模拟C的条件三元运算符。它可以作为包从在这里安装
该实现基于@kohske给出的答案,但我做了一些更改,以便它在if_true和if_false参数包含冒号的情况下是健壮的,允许条件语句被链接,并保留?操作符的基本功能。
我将参考其他人关于重新定义操作符的危险的警告,但这是R语言可以多么动态的一个很好的例子!
Tidyverse在dplyr库中有if_else()函数。与基础函数ifelse()相比,这个函数更加严格。它检查true和false是否为同一类型。这种严格性使输出类型更可预测,并使其更快。
if_else(a == 1, 1, 2)