【问题标题】:Is there a reason to prefer '&&' over '&' in 'if' statements, other than short-circuiting?除了短路之外,是否有理由在“if”语句中更喜欢“&&”而不是“&”?
【发布时间】:2015-07-06 02:11:00
【问题描述】:

是的,我知道,关于在 R 中使用 &&& 有很多问题(例如,请参阅 this one),但我还没有找到一个专门回答我的问题的问题。

据我了解,

  • & 进行元素方面的矢量化比较,就像其他算术运算一样。因此,如果两个参数的长度 > 1,它就会返回一个长度 > 1 的逻辑向量。
  • && 比较两个向量的第一个元素并始终返回长度为 1 的结果。此外,它会短路cond1 && cond2 && cond3 && ... 仅在 cond1TRUE 时评估 cond2 ,等等。这允许使用if(exists("is.R") && is.function(is.R) && is.R()) 之类的东西,特别是意味着在某些情况下使用&& 是绝对必要的。

此外,if 发出警告

条件的长度 > 1,并且只使用第一个元素

如果它的条件有多个元素。

从这些初步情况来看,我认为在所有不需要短路的if 语句中,首选& 而不是&& 更安全。

如果在计算过程中出现问题并且我不小心在& 的一个参数中包含了一个向量,我会收到一个警告,这很好。如果没有,一切都很好。

另一方面,如果我使用了&&,但我的计算出了点问题,而&& 的一个参数是向量,我不会收到警告。这是不好的。如果出于某种原因,我真的想比较两个向量的第一个元素,我认为显式而不是隐式这样做要干净得多。

请注意,这与 R 程序员之间似乎达成的共识相反,也与 R 文档的建议相反。 (1)

因此我的问题:除了短路之外,还有什么原因可以使&&if 语句中优于&


(1) 引用help(&&):

'&' 和 '&&' 表示逻辑 AND 和 '|'和'||'表明 逻辑或。较短的形式执行元素比较 与算术运算符的方式非常相似。较长的形式 从左到右求值,只检查每个元素的第一个元素 向量。仅在确定结果之前进行评估。 较长的形式适用于编程控制流和 通常在“if”子句中首选。

【问题讨论】:

  • 我基本上同意你的布局。注意:&& 稍微快一些(尽管可能无关紧要)。我主要使用&&,因为它允许短路。我也希望 R 有标量数据类型。不确定“按位”比较是什么意思;我认为这不适用于这些运营商。
  • @BrodieG 关于“按位”:说实话,我从this answer 那里得到了这个表达。我想你是对的,它不适用于这里;稍后我会删除它以避免混淆。

标签: r vectorization conventions


【解决方案1】:

,使用&& 除了短路之外没有任何优势。

但是,对于控制流来说,短路是非常可取的,因此它应该是默认设置。 if 语句不应采用矢量化参数 - 这就是 ifelse 的用途。如果您将逻辑向量传递给 if,通常您会使用 anyall 将其压缩为单个逻辑值以进行评估。

短路的主要优势在于避免冗长或容易出错的步骤(例如互联网连接 - 尽管这些应通过try 处理):

#avoiding lengthy calculations
system.time(if(FALSE & {Sys.sleep(2);TRUE}) print("Hello"))
   user  system elapsed 
   0.00    0.00    1.99 
system.time(if(FALSE && {Sys.sleep(2);TRUE}) print("Hello"))
   user  system elapsed 
      0       0       0 

#avoiding errors
if(FALSE & {stop("Connection Failed");TRUE}) print("Success") else print("Condition not met")
Error: Connection Failed
if(FALSE && {stop("Connection Failed");TRUE}) print("Success") else print("Condition not met")
[1] "Condition not met"

很明显,为了利用这些功能,您必须提前知道哪些步骤耗时最长或容易出错,并适当地构建逻辑语句。

【讨论】:

  • 好吧,我特意询问了除了短路以外的原因...当然,在您提到的情况下,使用&& 显然更可取/必要,但是就个人而言,我的代码中从未遇到过这种情况。这就是我问其他原因的原因。
  • 此外,我从未主张将if 与矢量化参数一起使用;相反:“我认为明确而不是隐含地这样做要干净得多。”
  • @jhin 是的,我知道你问了除了短路,但这个问题似乎没有意识到它的价值。一般来说,如果不需要,您不应该评估参数。使用& 时收到的警告很简单——程序的其余部分将继续运行。根据您的设置和执行的上下文,您甚至可能看不到它。 && 无论如何只会计算向量的第一个元素。
  • “一般来说,如果你不需要,你不应该评估参数。” ——我当然同意!而且我更喜欢这样一个“懒惰”(这是正确的术语吗?)运算符 ,它在应用于长度 > 1 的向量时也会发出警告。
  • "&& 无论如何只会计算向量的第一个元素。" - 是的,这正是我不喜欢它的地方。它甚至不发出警告,而是静默执行,尽管在许多情况下,标量或向量都会指示先前计算中的错误。
【解决方案2】:

简短回答:是的,不同的符号使读者更清楚地理解了含义。

感谢这个有趣的问题!如果我可以总结一下,这似乎是针对您链接的问题的my answer这一部分的专门跟进,

...只有在确定 向量长度为​​一。你应该绝对确定你的载体 长度仅为 1,例如在它们是函数的情况下 仅返回长度为 1 的布尔值。如果 向量的长度可能 > 1。所以如果你不确定,你 应该先检查,或者使用缩写形式,然后使用 all 和 any 将其缩短为长度一以用于控制流语句, 就像如果。

我这样听到你的问题(给定 cmets):但是如果输入长度为 1,&&& 会做同样的事情,所以除了短路之外,为什么更喜欢 &&?也许应该首选&,因为如果它们不是长度为一,if 会给我一个警告,帮助我更加确定输入的长度是一。

首先,我同意@James 的评论,您可能“夸大了收到警告的价值”;如果它不是长度一,更安全的事情是适当地处理它,而不是仅仅向前耕作。你可以假设&& 如果它们不是长度为 1 时应该抛出一个错误,这可能是一个很好的例子;我不知道它这样做的原因。但是,如果不回到过去,我们现在能做的最好的事情就是检查输入是否确实适合您的使用。

鉴于您已经检查以确保您的输入是适当的,我仍然推荐&&,因为它在语义上提醒我作为读者我应该确保输入是标量(长度为一)。我已经习惯了矢量盟友的想法,所以这个提醒对我很有帮助。它遵循不同操作应该有不同符号的原则,对我来说,用于标量的操作与矢量化操作有很大不同,因此它需要不同的符号。

(不要发动火焰战争(我希望),但这也是为什么我更喜欢<-而不是=;一个用于分配变量,一个用于为函数设置参数。虽然在内心深处这是一回事,它在实践中的不同足以使不同的符号对我作为读者有所帮助。)

【讨论】:

  • 您在这里提出的观点很有趣!我觉得有点矛盾。虽然我确实同意一个人应该(在视觉上)对标量和向量有不同的运算符,但让我伤心的是&&& 并没有足够不同,因为他们都乐于接受向量。显然,这是 R 的问题,而不是你的论点。
  • 啊,我想我可以更好地回应您的评论。不同的符号告诉我我应该处理标量,所以每当我看到这个时,我都会被提醒确保我已经进行了适当的检查。答案稍作修改以反映。
猜你喜欢
  • 1970-01-01
  • 2011-03-18
  • 2011-06-18
  • 2011-11-03
  • 1970-01-01
  • 2010-12-03
  • 1970-01-01
  • 1970-01-01
  • 2020-10-23
相关资源
最近更新 更多