John John - 14 days ago 8
R Question

Logical "and" for multiple logical vectors

If I have a number of logical statements (logical vectors in general), like

x>1
,
y!=1
and
sin(x)<0
, is there a function
AND
in R:

AND(x>1, y!=1, sin(x)<0)


giving the same results as

x>1 & y!=1 & sin(x)<0


Note, the number of vectors are variable, and not restricted to 3.

Answer

As mentioned by @r2evans, if we only work with scalar rather than vector, we can use all safely:

all(1 < 4, 5 > 7, 6 == 6)

My answer below addresses the case when you work with several logical vectors, and would like to take parallel / element-wise all. As a reproducible example, suppose we have logical vectors:

set.seed(0)

a1 <- sample(c(TRUE, FALSE), 5, replace = TRUE)
# [1] FALSE  TRUE  TRUE FALSE FALSE

a2 <- sample(c(TRUE, FALSE), 5, replace = TRUE)
# [1]  TRUE FALSE FALSE FALSE FALSE

a3 <- sample(c(TRUE, FALSE), 5, replace = TRUE)
# [1]  TRUE  TRUE  TRUE FALSE  TRUE

We aim for a solution that are not subject to the number of logical vectors.


Option 1

We can use Reduce and "&":

## define a function
AND1 <- function (...)  Reduce("&", list(...))

AND1(a1, a2, a3)
# [1] FALSE FALSE FALSE FALSE FALSE

The binary operator "&" only works with two inputs, so we can do

"&"(a1, a2)

but not

"&"(a1, a2, a3)

Reduce is here to help, by iteratively applying "&":

tmp <- "&"(a1, a2)
"&"(a2, a3)

The following two options first collect all logical vectors into a matrix. Then option 2a uses row-wise all, while option 2b uses rowSums.

Option 2a

AND2a <- function (...) {
  X <- do.call(cbind, list(...))
  base::apply(X, 1L, all)
  }

AND2a (a1, a2, a3)
# [1] FALSE FALSE FALSE FALSE FALSE

Option 2b

AND2b <- function (...) {
  X <- do.call(cbind, list(...))
  ## `TRUE` is 1 and `FALSE` is 0 when doing arithmetic sum
  ## all `TRUE` is as same as row sums equal to `ncol(X)` or `dim(X)[2]`
  base::rowSums(X) == dim(X)[2L]
  }

AND2b (a1, a2, a3)
# [1] FALSE FALSE FALSE FALSE FALSE