布尔运算符 && 和 ||
Posted
技术标签:
【中文标题】布尔运算符 && 和 ||【英文标题】:Boolean operators && and || 【发布时间】:2011-09-27 09:15:05 【问题描述】:根据R language definition,&
和&&
(对应|
和||
)的区别在于前者是矢量化的,而后者不是。
根据the help text,我读到的区别类似于“And”和“AndAlso”(相应地“Or”和“OrElse”)之间的区别...... 意义: 不是所有的评估都不是必须的(即,如果 A 为真,则 A、B 或 C 始终为真,因此停止评估 A 是否为真)
有人能解释一下吗? 另外,R 中是否有 AndAlso 和 OrElse?
【问题讨论】:
另请参阅***.com/q/6933598/210673 和***.com/q/7953833/210673 上的类似问题(现已作为副本关闭)。 我认为 && 和 ||在 R 中实现不好。在其他语言中,它们是条件 AND 和 OR 运算符,它们执行逻辑 AND 或 OR 布尔运算,但仅在必要时评估其第二个操作数。在 R 中不要做任何有用的事情。 @skan:我认为您声称&&
和 ||
的行为与未指定的“其他语言”不同,后者在第一个参数确定时不评估第二个参数,这只是 FALSE。
【参考方案1】:
较短的被向量化,这意味着它们可以返回一个向量,如下所示:
((-2:2) >= 0) & ((-2:2) <= 0)
# [1] FALSE FALSE TRUE FALSE FALSE
较长的形式从左到右只检查每个向量的第一个元素,所以上面给出了
((-2:2) >= 0) && ((-2:2) <= 0)
# [1] FALSE
正如帮助页面所说,这使得较长的形式“适用于编程控制流,并且通常在 if 子句中首选。”
因此,只有当您确定向量的长度为 1 时,您才想使用长格式。
您应该绝对确定您的向量的长度仅为 1,例如在它们是仅返回长度为 1 布尔值的函数的情况下。如果向量的长度可能 > 1,您想使用简短形式。因此,如果您不确定,您应该先检查,或者使用缩写形式,然后使用 all
和 any
将其缩短为长度,以便在控制流语句中使用,例如 if
。
函数all
和any
经常用于向量化比较的结果,以分别查看所有或任何比较是否为真。这些函数的结果肯定长度为 1,因此它们适用于 if 子句,而矢量化比较的结果则不然。 (尽管这些结果适用于ifelse
。
最后一个区别:&&
和 ||
只评估所需数量的术语(这似乎是短路的意思)。例如,这是使用未定义值a
进行的比较;如果它没有短路,就像&
和|
那样,它会报错。
a
# Error: object 'a' not found
TRUE || a
# [1] TRUE
FALSE && a
# [1] FALSE
TRUE | a
# Error: object 'a' not found
FALSE & a
# Error: object 'a' not found
最后,请参阅The R Inferno 中的第 8.2.17 节,标题为“and and andand”。
【讨论】:
我正在比较长度为 1 的逻辑。文档不清楚为什么它更适合控制流。那是因为它使用了@Theo 答案中的“短路”,因此具有更好的性能? 不。只需使用缩写形式 '&' - 短路答案不正确。 否,因为它保证只有一个 TRUE/FALSE 答案。较短的形式可能导致c(TRUE, FALSE)
,而if
语句将不清楚。如果您确定所有内容的长度都为 1,那么是的,任何一个都可以,并且您是正确的,“短路”是首选之一的原因。不过要提醒一句,请确保您 100% 确定它们只能是长度为 1。否则你会得到非常愚蠢的错误。
@SFun28:是的,短路是流量控制首选的原因。除了更好的性能外,您可能不想评估所有参数。 ?is.R
中给出了规范示例,用于检查您运行的是 R 还是 S-Plus。 if(exists("is.R") && is.function(is.R) && is.R())
。如果is.R
不存在,那么您不想评估is.function(is.R)
,因为它会引发错误。同样,如果 is.R
不是一个函数,你也不想像它是一样调用它。
在当前版本的 R inferno 中,相关部分现在是 8.2.17 "and and andand"【参考方案2】:
关于"short-circuiting" 的答案可能具有误导性,但有一些道理(见下文)。在 R/S 语言中,&&
和 ||
仅计算第一个参数中的第一个元素。无论第一个值如何,向量或列表中的所有其他元素都将被忽略。这些运算符旨在与if (cond) else
构造一起使用并指导程序控制而不是构造新向量。&
和|
运算符旨在处理向量,因此它们将“并行”应用,可以这么说,沿着最长参数的长度。在进行比较之前,需要对两个向量进行评估。如果向量的长度不同,则执行较短参数的循环。
当&&
或||
的参数被计算时,存在“短路”,如果从左到右连续的任何值是确定性的,则计算停止并返回最终值。
> if( print(1) ) print(2) else print(3)
[1] 1
[1] 2
> if(FALSE && print(1) ) print(2) else print(3) # `print(1)` not evaluated
[1] 3
> if(TRUE && print(1) ) print(2) else print(3)
[1] 1
[1] 2
> if(TRUE && !print(1) ) print(2) else print(3)
[1] 1
[1] 3
> if(FALSE && !print(1) ) print(2) else print(3)
[1] 3
只有当参数需要很长时间来评估时,短路的优势才会出现。当参数是处理较大对象或具有更复杂的数学运算的函数时,通常会发生这种情况。
【讨论】:
“短路”对我来说是一个新词,但在我看来,描述它的答案与你所说的&&
和 ||
一致。
@DWin - 在对长度为 1 的逻辑进行操作的情况下,它们是等价的吗?正如文档所述,我试图理解为什么它们在控制流中是首选的。另外,R 是否有“短路”结构?
它们不等价于长度> 1的向量
确实,如果&&
的参数是函数并且第一个为false,则不会计算第二个。对于将评估两个参数的&
或ifelse
都不是这样。
@dez93 TRUE 在“&&”之前不是决定性的。而那些并没有真正返回 1,而是在分别返回 2 和 3 之前打印 1 作为 print
函数评估的副作用。打印 1 作为 TRUE' 在那一点上不是决定性的标志。在第 5 个实例中没有 1 打印到控制台,因为 FALSE 是“&&”表达式的决定性因素,因为第二个参数的值无关紧要。如果我将 if 子句的结果分配给命名变量,我们可以更清楚地看到情况。【参考方案3】:
&&
和||
就是所谓的“短路”。这意味着如果第一个操作数足以确定表达式的值,它们将不会计算第二个操作数。
例如,如果&&
的第一个操作数为假,则计算第二个操作数没有意义,因为它不能更改表达式的值(false && true
和false && false
都是假的)。当第一个操作数为真时,||
也是如此。
您可以在此处阅读更多相关信息:http://en.wikipedia.org/wiki/Short-circuit_evaluation 从该页面上的表格中您可以看到 &&
相当于 VB.NET 中的 AndAlso
,我假设您指的是它。
【讨论】:
这应该足以证明它正在短路:f <- function() print('hello'); TRUE ; FALSE && f()
。更改为 &
并注意该函数已被评估。 QED。
Theo,是的,你是正确的 &&
和 ||
短路。但这在短格式和长格式之间的比较中确实是一个相当小的点。当输入是向量时,了解每个函数的作用更为重要。
@MTibbits 其实这不是一个完整的答案,但是关于短路的说法是正确的。试试F & message("Boo!");T
和F && message("Boo!");T
。以上是关于布尔运算符 && 和 ||的主要内容,如果未能解决你的问题,请参考以下文章