Mathematica 的Which
函数是一个广义的If
:
Which[test_1, value_1, test_2, value_2, …]
依次评估每个
test_i
,返回与产生value_i
的第一个True
对应的if (test_1) value_1 else if (test_2) value_2 else ... value_n else default
的值。
它只是一种方便的方法,可以从嵌套的简单if-else测试的长序列中删除多余的语法。
R是否具有等效功能?
顺便说一句,我知道我总能做点什么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
...但结果对测试的形状很敏感,因此它并不严格等同于嵌套的switch
语句。
最后,R switch(expr,
case_1 = value_1,
case_2 = value_2,
...
case_n = value_n,
default)
声明与我正在寻找的声明类似,因为它将调度封装在一系列测试中,但它并不完全相同事情。在
expr
...测试都是case_i
与Which
的相等比较,而在{{1}}等中,测试是任意的布尔表达式。
答案 0 :(得分:3)
根据Mathematica的帮助,
其中[test1,value1,test2,value2,...] 依次评估每个testi,返回对应于产生True的第一个值的valuei的值。
我们可以在R中执行此操作,即获取与计算结果为true的第一个表达式的位置对应的值,如下所示:
<强> 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"
虽然,如果没有一个表达式为真,which.max将返回第一个false,所以我们也应检查这个
if (any(expressions)) values[which.max(expressions)] else NA
<强> 2。版本“短路”
然而,Mathematica的上述行为存在一个差异:mathematica短路中的which
- 即它只评估找到第一个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)]
答案 1 :(得分:1)
您可以编写自己的函数,可以用作这样的控制结构。接下来是基于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
}
副作用可用于查看实际评估的内容。
例如:
> 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)
。