首页 文章

R中“&&”和“||”运算符的实际用途是什么?

提问于
浏览
0

主要问题

In what practical programming situations or R "idioms" would you only want to check the first element of each of two vectors for logical comparison? (I.e. disregarding the rest of each vector as in && and ||.)

我可以在R中看到 &| 的使用,它们在两个向量的元素方式逻辑比较中 . 但我看不到他们兄弟操作员 &&|| 的真实生活实际用途 . 任何人都可以提供他们使用的明确例子吗?

文档 help("&&") 说:

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

我的问题如下:我将 &&|| 的文档解释为对于逻辑向量 xy&&|| 运算符仅使用 x[1]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

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

1 回答

  • 3

    我想有几个原因,但最重要的可能是短路行为 . 如果 aa && 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 条件中使用 & ,因为您的索引将超出范围,并且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
    

相关问题