布尔运算符 && 和 ||

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,您想使用简短形式。因此,如果您不确定,您应该先检查,或者使用缩写形式,然后使用 allany 将其缩短为长度,以便在控制流语句中使用,例如 if

函数allany 经常用于向量化比较的结果,以分别查看所有或任何比较是否为真。这些函数的结果肯定长度为 1,因此它们适用于 if 子句,而矢量化比较的结果则不然。 (尽管这些结果适用于ifelse

最后一个区别:&amp;&amp;|| 只评估所需数量的术语(这似乎是短路的意思)。例如,这是使用未定义值a 进行的比较;如果它没有短路,就像&amp;| 那样,它会报错。

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") &amp;&amp; is.function(is.R) &amp;&amp; is.R())。如果is.R 不存在,那么您不想评估is.function(is.R),因为它会引发错误。同样,如果 is.R 不是一个函数,你也不想像它是一样调用它。 在当前版本的 R inferno 中,相关部分现在是 8.2.17 "and and andand"【参考方案2】:

关于"short-circuiting" 的答案可能具有误导性,但有一些道理(见下文)。在 R/S 语言中,&amp;&amp;|| 仅计算第一个参数中的第一个元素。无论第一个值如何,向量或列表中的所有其他元素都将被忽略。这些运算符旨在与if (cond) else 构造一起使用并指导程序控制而不是构造新向量。&amp;| 运算符旨在处理向量,因此它们将“并行”应用,可以这么说,沿着最长参数的长度。在进行比较之前,需要对两个向量进行评估。如果向量的长度不同,则执行较短参数的循环。

&amp;&amp;|| 的参数被计算时,存在“短路”,如果从左到右连续的任何值是确定性的,则计算停止并返回最终值。

> 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

只有当参数需要很长时间来评估时,短路的优势才会出现。当参数是处理较大对象或具有更复杂的数学运算的函数时,通常会发生这种情况。

【讨论】:

“短路”对我来说是一个新词,但在我看来,描述它的答案与你所说的 &amp;&amp;|| 一致。 @DWin - 在对长度为 1 的逻辑进行操作的情况下,它们是等价的吗?正如文档所述,我试图理解为什么它们在控制流中是首选的。另外,R 是否有“短路”结构? 它们等价于长度> 1的向量 确实,如果&amp;&amp; 的参数是函数并且第一个为false,则不会计算第二个。对于将评估两个参数的&amp;ifelse 都不是这样。 @dez93 TRUE 在“&&”之前不是决定性的。而那些并没有真正返回 1,而是在分别返回 2 和 3 之前打印 1 作为 print 函数评估的副作用。打印 1 作为 TRUE' 在那一点上不是决定性的标志。在第 5 个实例中没有 1 打印到控制台,因为 FALSE 是“&&”表达式的决定性因素,因为第二个参数的值无关紧要。如果我将 if 子句的结果分配给命名变量,我们可以更清楚地看到情况。【参考方案3】:

&amp;&amp;|| 就是所谓的“短路”。这意味着如果第一个操作数足以确定表达式的值,它们将不会计算第二个操作数。

例如,如果&amp;&amp; 的第一个操作数为假,则计算第二个操作数没有意义,因为它不能更改表达式的值(false &amp;&amp; truefalse &amp;&amp; false 都是假的)。当第一个操作数为真时,|| 也是如此。

您可以在此处阅读更多相关信息:http://en.wikipedia.org/wiki/Short-circuit_evaluation 从该页面上的表格中您可以看到 &amp;&amp; 相当于 VB.NET 中的 AndAlso,我假设您指的是它。

【讨论】:

这应该足以证明它正在短路:f &lt;- function() print('hello'); TRUE ; FALSE &amp;&amp; f()。更改为 &amp; 并注意该函数已被评估。 QED。 Theo,是的,你是正确的 &amp;&amp;|| 短路。但这在短格式和长格式之间的比较中确实是一个相当小的点。当输入是向量时,了解每个函数的作用更为重要。 @MTibbits 其实这不是一个完整的答案,但是关于短路的说法是正确的。试试F &amp; message("Boo!");TF &amp;&amp; message("Boo!");T

以上是关于布尔运算符 && 和 ||的主要内容,如果未能解决你的问题,请参考以下文章

javaScript 中的布尔运算符 && 和 ||

&= 和 |= 运算符是不是用于布尔短路?

布尔逻辑运算符

js || &&

||和|,&&和&的区别

java的布尔运算符和位运算符