turtlegraphics
turtlegraphics

Reputation: 296

What is going on with R coercing "TRUE" string to TRUE logical?

So, I discovered this:

> TRUE == "TRUE"
[1] TRUE
> TRUE == "BOO"
[1] FALSE
> TRUE == "true"
[1] FALSE
> TRUE == "T"
[1] FALSE
> FALSE == "FALSE"
[1] TRUE
> FALSE == "F"
[1] FALSE

According to the R documentation for logical {base}:

as.logical attempts to coerce its argument to be of logical type. Character strings c("T", "TRUE", "True", "true") are regarded as true, c("F", "FALSE", "False", "false") as false, and all others as NA.

This is actually the case:

> as.logical("T")
[1] TRUE

So apparently, what's going on with TRUE == "T" is not an as.logical sort of conversion. Is there any reasonable explanation for the behavior of these == comparisons?

Upvotes: 7

Views: 10815

Answers (3)

Petr Matousu
Petr Matousu

Reputation: 3140

Better to use isTRUE

> isTRUE 
function (x) 
identical(TRUE, x)
<bytecode: 0x82228c8>
<environment: namespace:base>

> isTRUE("T")
[1] FALSE
> isTRUE(T)
[1] TRUE
> isTRUE(TRUE)
[1] TRUE
> isTRUE("TRUE")
[1] FALSE 
> isTRUE("anything")
[1] FALSE
> isTRUE(1L)
[1] FALSE
> isTRUE(c(TRUE,TRUE))
[1] FALSE
> 
> isTRUE(any(c(TRUE,TRUE)))
[1] TRUE
> isTRUE(all(c(TRUE,TRUE)))
[1] TRUE

> answer <- "yes"
> isTRUE(answer %in% c("Y","Yes","y","yes"))
[1] TRUE
> answer <- "no"
> isTRUE(answer %in% c("Y","Yes","y","yes"))
[1] FALSE
> answer <- c("Y","n")
> isTRUE(answer %in% c("Y","Yes","y","yes"))
[1] FALSE

Upvotes: 1

Carl Boneri
Carl Boneri

Reputation: 2722

In terms of your question I'm having trouble imagining a scenario in which you would evaluate TRUE == "TRUE", vs "TRUE" == TRUE. For instance; take a wrapper function that we can run all scenarios for your variables and iterate them through tests for as.logical, is.logical, x == TRUE, x == FALSE, x != TRUE etc...

What our testing function will do is take an input and only return the scenarios that evaluate to TRUE in terms of a logical test in an R function.

f <-function(var){
  do_fun <- list(
    `%s == TRUE` = function(x)x==TRUE,
    `%s == FALSE` = function(x)x == FALSE,
    `as.logical(%s)` = function(x)as.logical(x),
    `is.logical(%s)` = function(x)is.logical(x))

  a <- sapply(names(do_fun), function(i){
    do.call(do_fun[[i]],list(var))
  })
  set_name <- sprintf(names(a),var)
  a <- as.list(a)
  names(a) <- set_name
  a[sapply(a,`[`,1)]

}

Testing on TRUE

# from base test to show
> is.logical(TRUE)
[1] TRUE

Now with our testing fun

> f(TRUE)
$`TRUE == TRUE`
[1] TRUE

$`as.logical(TRUE)`
[1] TRUE

$`is.logical(TRUE)`
[1] TRUE

As strings instead of reserved characters

> f("true")
$`as.logical("true")`
[1] TRUE

> f("TRUE")
$`"TRUE" == TRUE`
[1] TRUE

$`as.logical("TRUE")`
[1] TRUE

On numeric values the output logical is based on the evaluation of the input rather than the class

> f(10.1)
$`as.logical(10.1)`
[1] TRUE

> f(10.1 > 1)
$`TRUE == TRUE`
[1] TRUE

$`as.logical(TRUE)`
[1] TRUE

$`is.logical(TRUE)`
[1] TRUE

or

> f(1+1)
$`as.logical(2)`
[1] TRUE

Upvotes: 3

R.S.
R.S.

Reputation: 2140

Here's what I made of it: From the documentation of logical comparisons ?"==":

At least one of x and y must be an atomic vector, but if the other is a list R attempts to coerce it to the type of the atomic vector: this will succeed if the list is made up of elements of length one that can be coerced to the correct type. If the two arguments are atomic vectors of different types, one is coerced to the type of the other, the (decreasing) order of precedence being character, complex, numeric, integer, logical and raw.

To me it seems like the latter part of this is at work here. TRUE is being coerced to "TRUE" and the actual comparison becomes "TRUE"=="TRUE" instead of TRUE==TRUE.

T always gets converted to TRUE so T=="TRUE" holds. However ``"T"` has no such luck when conversion is to happen to.character and not to.logical. .

Upvotes: 4

Related Questions