布尔运算符&&和||


252

根据R输入语言定义,之间的差&&&(相应地|||)是,前者被矢量而后者则不是。

根据帮助文本,我读到了与“ And”和“ AndAlso”(相应地为“ Or”和“ OrElse”)之间的区别类似的含义……含义:并非所有评估都必须是(即,如果A为true,则A或B或C始终为true,因此,如果A为true,则停止评估)

有人可以照亮这里吗?另外,R中是否有AndAlso和OrElse?


另请参阅stackoverflow.com/q/6933598/210673stackoverflow.com/q/7953833/210673(现在已作为副本关闭)中的类似问题。
亚伦(Aaron)

3
我认为&&和|| 在R中不好实现。在其他语言中,它们是条件AND和OR运算符,它们执行逻辑AND或OR布尔运算,但仅在必要时才求值第二个操作数。在R中不要做任何有用的事情。
skan

Answers:


340

较短的向量被向量化,这意味着它们可以返回向量,如下所示:

((-2:2) >= 0) & ((-2:2) <= 0)
# [1] FALSE FALSE  TRUE FALSE FALSE

较长的形式仅检查每个向量的第一个元素就从左到右求值,因此以上给出

((-2:2) >= 0) && ((-2:2) <= 0)
# [1] FALSE

就像帮助页面所说的那样,这使得较长的形式“适合编程控制流,并且[在]子句中通常是首选的”。

因此,仅在确定向量的长度为一时,才想使用长格式。

您应该绝对确定向量仅是长度1,例如在它们是仅返回长度1布尔值的函数的情况下。如果向量的长度可能大于1,则要使用缩写形式。因此,如果您不确定,则应该先检查,或者使用缩写形式,然后使用all并将any其减小为长度,以便在控制流语句中使用,例如if

函数allany通常用于向量化比较的结果,以分别查看所有比较或所有比较是否为真。这些函数的结果肯定为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答案中的“短路”并因此具有更好的性能?
SFun28

不。只需使用缩写形式'&'-短路答案不正确。
M. Tibbits,

1
不,因为它保证只有一个TRUE / FALSE答案。较短的形式可能会导致c(TRUE, FALSE),并且该if语句不清楚。如果确定所有长度都为1,则可以,两者之一都可以,并且您正确地认为“短路”是首选长度的原因。不过请注意,请确保您100%确保它们只能是长度1。否则,您可能会得到一些愚蠢的错误。
亚伦(Aaron)

9
@ SFun28:是的,短路是流量控制首选的原因。除了更好的性能外,您可能不想评估所有参数。给出了规范的示例,?is.R用于检查您是否正在运行R或S-Plus。 if(exists("is.R") && is.function(is.R) && is.R())。如果is.R不存在,则您不希望评估,is.function(is.R)因为它将抛出错误。同样,如果is.R不是函数,则不要像调用函数那样调用它。
Richie Cotton

2
在当前版本的R inferno中,相关部分现在为8.2.17“ and and andand”
Silverfish

34

关于“短路”的答案可能会引起误解,但有一定道理(见下文)。在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

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


“短路”对我来说是个新名词,但在我看来,描述它的答案与您所说的&&和一致||
亚伦(Aaron)

@DWin-在操作长度超过1的逻辑时,它们等效吗?我试图理解为什么文档说明指出它们在控制流中是首选的。另外,R是否具有“短路”结构?
SFun28

它们不适用于长度> 1
M的

2
的确,如果to的参数&&是函数,而第一个参数为false,则不会计算第二个参数。对于任何一个都不是正确的,&否则ifelse将对两个参数都求值。
IRTFM

那不是Theo关于短路的答案吗?
亚伦(Aaron)

25

&&||在所谓的“短路”。这意味着,如果第一个操作数足以确定表达式的值,则他们将不会评估第二个操作数。

例如,如果to的第一个操作数&&为false,则评估第二个操作数没有意义,因为它不能更改表达式的值(false && true并且false && false都为false)。第||一个操作数为true时也是如此。

您可以在此处阅读有关此内容的更多信息:http : //en.wikipedia.org/wiki/Short-circuit_evaluation从该页面上的表中,您可以看到&&AndAlsoVB.NET中的等效,我假设您所指的是VB.NET。


3
这应该足以证明它存在短路:f <- function() { print('hello'); TRUE }; FALSE && f()。转到&并注意该函数已被评估。QED。
Theo

2
西奥,是的,你是正确的,&&并且||短路。但这在短格式和长格式之间的比较中确实是一个次要的问题;了解输入为向量时每个函数的作用更为重要。
亚伦(Aaron)

2
@MTibbits实际上,这不是一个完整的答案,但是有关短路的说法是正确的。尝试F & {message("Boo!");T}F && {message("Boo!");T}
mbq 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.