【问题标题】:What are practical uses of the "&&" and "||" operators in R?“&&”和“||”的实际用途是什么R中的运算符?
【发布时间】:2014-07-23 22:48:57
【问题描述】:

主要问题

在哪些实际的编程情况或 R“习语”中,您只想检查两个向量中每个向量的第一个元素以进行逻辑比较? (即忽略每个向量的其余部分,如 &&||。)

我可以看到&| 在 R 中的使用,它们在其中对两个向量进行逐元素逻辑比较。但我看不到他们的兄弟运算符&&|| 在现实生活中的实际使用。任何人都可以提供一个明确的使用示例吗?

文档help("&&")说:

较长的形式从左到右计算,只检查每个向量的第一个元素。 仅在确定结果之前进行评估。 较长的形式适用于 编程控制流,通常在 if 子句中首选。

对我来说问题如下:我将&&|| 的文档解释为对于逻辑向量xy&&|| 运算符仅使用@987654334 @ 和 y[1] 提供结果。

> c(TRUE, FALSE, FALSE) && c(TRUE, FALSE)
[1] TRUE

> c(TRUE, FALSE, FALSE) && c(FALSE, FALSE)
[1] FALSE

> c(FALSE, FALSE, FALSE) && c(TRUE, FALSE)
[1] FALSE

> c(FALSE, FALSE, FALSE) && c(FALSE, FALSE)
[1] FALSE

我没有看到任何“编程控制流”情况,其中我有两个逻辑向量并且我会忽略每个超过第一个元素的任何值。

似乎x && y 的行为类似于x[1] & y[1],而x || y 的行为类似于x[1] | y[1]

基准

这是一个测试函数,它使用随机生成的不同长度的逻辑向量来评估这些公式返回相同结果的频率。这表明他们正在做同样的事情。

> test <- function( n, maxl=10 ) {
    foo <- lapply( X=seq_len( n ), FUN=function(i) { 
        x <- runif( n=sample( size=1, maxl ) ) > 0.5
        y <- runif( n=sample( size=1, maxl ) ) > 0.5
        sameres <- all.equal( (x||y), (x[1]|y[1]) )
        sameres
    } )

    table( unlist( foo ) )
}
test( 10000 )

产量:

TRUE 
 10000 

这是一个更快的基准测试。它首先创建一个列表列表,其中dat 中的每个N 项目是一个包含两个随机生成的逻辑向量的列表。然后我们将每个变体应用到相同的数据上,看看哪个更快。

library(rbenchmark)
N <- 100
maxl <- 10
dat <- lapply( X=seq_len(N), FUN=function(i) { 
    list( runif( n=sample( size=1, maxl ) ) > 0.5, 
          runif( n=sample( size=1, maxl ) ) > 0.5) } )
benchmark( 
    columns=c("test","replications","relative"),
    lapply(dat, function(L){ L[[1]]    || L[[2]]    } ), 
    lapply(dat, function(L){ L[[1]][1] |  L[[2]][1] } ) 
)

产生以下输出(删除了 \n 字符和多余的空格):

                                                test replications relative
2 lapply(dat, function(L) { L[[1]][1] | L[[2]][1] })          100    1.727
1 lapply(dat, function(L) { L[[1]]   || L[[2]]    })          100    1.000

显然,|| 公式比挑选每个参数的第一个元素要快。但我仍然很好奇为什么需要这样的操作员。

【问题讨论】:

  • 如果调用的是一系列由&amp;&amp; 连接的函数,那么第一个为假的函数将终止该过程,从而节省时间。对&amp; 的调用总是评估它们的所有参数。
  • 如果您在if 子句中有c(TRUE, FALSE, FALSE) &amp;&amp; c(TRUE, FALSE),您可能需要考虑使用不同的if 子句。
  • 这就像在问为什么 C 有 &amp;&amp;/||&amp;/|
  • @HongOoi 有点不同,因为在 C 中 &amp;| 是按位的,而在 R 中则不是。
  • @GaborCsardi 我意识到这一点,但关键是运营商服务于不同的目的。一组用于流量控制。另一组用于按位运算(在 C 中)或矢量化操作(在 R 中)。

标签: r operators logical-operators


【解决方案1】:

我想有几个原因,但最重要的一个可能是短路行为。如果aa &amp;&amp; b 中计算为FALSE,则不计算b。同样,如果aa || b 中计算为TRUE,则不计算b。这允许编写类似的代码

v <- list(1, 2, 3, 4, 5)
idx <- 6
if (idx < length(v) && v[[idx]] == 5) {
  foo
} else {
  bar
}

否则需要将这个(可能)写成

if (idx < length(v)) {
  if (v[idx] == 5) {
    foo
  } else {
    bar
  }
} else {
  bar
}

这 1) 可读性大大降低,2) 重复 bar,如果 bar 是一段更大的代码,那就不好了。

您不能在if 条件中使用&amp;,因为您的索引会超出范围,而R 中的列表不允许这样做:

if (idx < length(v) & v[[idx]] == 5) {
  foo
} else {
  bar
}
# Error in v[[idx]] : subscript out of bounds

这里是短路行为的一个小例子:

t <- function() { print("t called"); TRUE }
f <- function() { print("f called"); FALSE }

f() && t()
# [1] "f called"
# [1] FALSE
f() & t()
# [1] "f called"
# [1] "t called"
# [1] FALSE

t() || f()
# [1] "t called"
# [1] TRUE
t() | f()
# [1] "t called"
# [1] "f called"
# [1] TRUE

【讨论】:

    猜你喜欢
    • 2012-12-31
    • 2011-10-29
    • 2011-04-02
    • 2019-05-17
    • 2015-04-22
    • 2021-07-22
    • 1970-01-01
    • 2018-03-09
    • 1970-01-01
    相关资源
    最近更新 更多