等同于 Mathematica 的 Which
Equivalent of Mathematica's Which
Mathematica 的 Which
函数是广义的 If
:
Which[test_1, value_1, test_2, value_2, …]
evaluates each of the test_i
in turn, returning the value of the value_i
corresponding to the first one that yields True
.
它只不过是一种从嵌套的简单 if-else 测试的长序列中删除多余语法的简便方法。
R 有等效的功能吗?
顺便说一句,我知道我总是可以做类似
的事情
if (test_1) value_1 else if (test_2) value_2 else ... value_n else default
或者,等价地,
if (test_1) value_1 else
if (test_2) value_2 else
...
if (test_n) value_n else
default
...但是,正如我已经提到的,与 Which
相比,嵌套的 if-else
语句引入了很多多余的语法。
此外,我知道
ifelse(t_1, v_1, ifelse(t_2, v_2, ..., ifelse(t_n, v_n, default)...))
...但结果对测试的形状很敏感,因此它并不严格等同于嵌套 if-else
语句。
最后,R 的 switch
语句与我正在寻找的相似,因为它封装了对一系列测试的调度,但这并不完全相同。在
switch(expr,
case_1 = value_1,
case_2 = value_2,
...
case_n = value_n,
default)
...测试都是 expr
与 case_i
的相等比较,而在 Which
等中,测试是任意布尔表达式。
根据 Mathematica 帮助,
Which[test1,value1,test2,value2,…] evaluates each of the testi in turn, returning the value of the valuei corresponding to the first one that yields True.
我们可以在 R 中执行此操作,即获取与计算结果为真的第一个表达式的位置对应的值,如下所示:
1.计算所有表达式的简单版本:
values = c("value1", "value2", "value3", "value4", "value5", "value6", "value7")
expressions = c(1==2, 1==3, 1==1, 1==4, T==F, F==T, T==T)
values[which.max(expressions)]
# [1] "value3"
虽然,如果 none 的表达式为真,which.max 将 return 第一个为假,所以我们也应该检查这个
if (any(expressions)) values[which.max(expressions)] else NA
2。 'short circuits'
的版本
但是,上面的行为与 Mathematica 有一个区别:which
在 Mathematica 短路中 - 即它只计算找到第一个 TRUE 所需的尽可能多的表达式。如果表达式的计算成本很高或存在速度瓶颈,那么我们可能还想在 R 中复制这种行为。我们可以使用 Position
来实现这一点,它会短路,并结合 eval(parse)
来确保我们在我们准备好测试它们之前不要评估表达式
values = c("value1", "value2", "value3", "value4", "value5", "value6", "value7")
expressions = c("1==2", "1==3", "1==1", "1==4", "T==F", "F==T", "T==F")
values[Position(function(text) eval(parse(text=text)), expressions, T)]
您可以编写自己的函数,用作此类控制结构。以下是基于 match.call
支持惰性求值的事实。 (参见 this 接受的答案):
which.val <- function(...){
clauses <- match.call(expand.dots = FALSE)$`...`
n <- length(clauses)
for(i in seq(1,n,2)){
condition = eval(clauses[[i]], envir = parent.frame())
if(condition) return(eval(clauses[[i+1]], envir = parent.frame()))
}
}
出于测试目的:
test <- function(a,b){
print(b)
a == b
}
可以通过side effect看实际评价的是什么。
例如:
> x <- 3
> which.val(test(x,1),10,test(x,2),20,test(x,3),30,test(x,4),40)
[1] 1
[1] 2
[1] 3
[1] 30
请注意 test(x,4)
从未被计算过。
Mathematica 的 Which
函数是广义的 If
:
Which[test_1, value_1, test_2, value_2, …]
evaluates each of the
test_i
in turn, returning the value of thevalue_i
corresponding to the first one that yieldsTrue
.
它只不过是一种从嵌套的简单 if-else 测试的长序列中删除多余语法的简便方法。
R 有等效的功能吗?
顺便说一句,我知道我总是可以做类似
的事情if (test_1) value_1 else if (test_2) value_2 else ... value_n else default
或者,等价地,
if (test_1) value_1 else
if (test_2) value_2 else
...
if (test_n) value_n else
default
...但是,正如我已经提到的,与 Which
相比,嵌套的 if-else
语句引入了很多多余的语法。
此外,我知道
ifelse(t_1, v_1, ifelse(t_2, v_2, ..., ifelse(t_n, v_n, default)...))
...但结果对测试的形状很敏感,因此它并不严格等同于嵌套 if-else
语句。
最后,R 的 switch
语句与我正在寻找的相似,因为它封装了对一系列测试的调度,但这并不完全相同。在
switch(expr,
case_1 = value_1,
case_2 = value_2,
...
case_n = value_n,
default)
...测试都是 expr
与 case_i
的相等比较,而在 Which
等中,测试是任意布尔表达式。
根据 Mathematica 帮助,
Which[test1,value1,test2,value2,…] evaluates each of the testi in turn, returning the value of the valuei corresponding to the first one that yields True.
我们可以在 R 中执行此操作,即获取与计算结果为真的第一个表达式的位置对应的值,如下所示:
1.计算所有表达式的简单版本:
values = c("value1", "value2", "value3", "value4", "value5", "value6", "value7")
expressions = c(1==2, 1==3, 1==1, 1==4, T==F, F==T, T==T)
values[which.max(expressions)]
# [1] "value3"
虽然,如果 none 的表达式为真,which.max 将 return 第一个为假,所以我们也应该检查这个
if (any(expressions)) values[which.max(expressions)] else NA
2。 'short circuits'
的版本但是,上面的行为与 Mathematica 有一个区别:which
在 Mathematica 短路中 - 即它只计算找到第一个 TRUE 所需的尽可能多的表达式。如果表达式的计算成本很高或存在速度瓶颈,那么我们可能还想在 R 中复制这种行为。我们可以使用 Position
来实现这一点,它会短路,并结合 eval(parse)
来确保我们在我们准备好测试它们之前不要评估表达式
values = c("value1", "value2", "value3", "value4", "value5", "value6", "value7")
expressions = c("1==2", "1==3", "1==1", "1==4", "T==F", "F==T", "T==F")
values[Position(function(text) eval(parse(text=text)), expressions, T)]
您可以编写自己的函数,用作此类控制结构。以下是基于 match.call
支持惰性求值的事实。 (参见 this 接受的答案):
which.val <- function(...){
clauses <- match.call(expand.dots = FALSE)$`...`
n <- length(clauses)
for(i in seq(1,n,2)){
condition = eval(clauses[[i]], envir = parent.frame())
if(condition) return(eval(clauses[[i+1]], envir = parent.frame()))
}
}
出于测试目的:
test <- function(a,b){
print(b)
a == b
}
可以通过side effect看实际评价的是什么。
例如:
> x <- 3
> which.val(test(x,1),10,test(x,2),20,test(x,3),30,test(x,4),40)
[1] 1
[1] 2
[1] 3
[1] 30
请注意 test(x,4)
从未被计算过。