The R language has two AND operators: &
and &&
. Knowing the difference is key when working with if
clauses.
The R documentation states that:
The longer form the left to right examining only the first element of each vector. Evaluation proceeds only until the result is determined. The longer form is appropriate for programming control-flow and typically preferred in if clauses.<
Consider the following variables:
The code below produces a logical vector of size 2: the evaluation is done for each of the elements.
The second example below ends up testing the first element of each vector (i.e. x[[1]] == 1 & y[[1]] == 1
) and produces a single value (TRUE & FALSE = FALSE
).
The last example produces TRUE
as both the first value of x
is equal to 1
and the first value of y
is equal to 2
.
Note that if the comparison is done on vectors of different lengths, operator &
will throw a warning.
Operator &&
will not complain.
Practical case
Suppose that you are writing the following R function:
Le’s run the function.
So far, so good. But what happens when you pass NULL
?
You got an error because is.na(NULL)
returns a logical vector of size 0 that is not compatible with the if
statement. So you adjust naively your function as follows:
It still fails because the &
operator evaluates is.na
even when the first condition has been made. Adding the &&
operator fixes the issue:
The &&
operator is more in line with .NET for example where additional conditions may not be evaluated based on result of previous conditions. On a side note, in .NET, the & operator performs bitwise AND operation.
Finally, and to be complete, passing a vector of length greater than 1
will produce the following:
You may want to use expressions such as any(is.na(x))
to check if any of the elements in x
are unknown.
Recap
I have compiled below the output of the &
and &&
operators based on different parameters.
x | print(x) | length(x) | !is.null(x) && !is.na(x) | !is.na(x) && !is.null(x) | !is.null(x) & !is.na(x) |
---|---|---|---|---|---|
NULL | NULL | 0 | [1] FALSE | [1] FALSE [Warning: is.na() applied to non-(list or vector) of type ‘NULL’] | logical(0) [Warning: is.na() applied to non-(list or vector) of type ‘NULL’] |
as.numeric(0) | [1] 0 | 1 | [1] TRUE | [1] TRUE | [1] TRUE |
as.numeric(NA) | [1] NA | 1 | [1] FALSE | [1] FALSE | [1] FALSE |
c(1, as.numeric(NA)) | [1] 1 NA | 2 | [1] TRUE | [1] TRUE | [1] TRUE FALSE |
c(as.numeric(NA), 1) | [1] NA 1 | 2 | [1] FALSE | [1] FALSE | [1] FALSE TRUE |