Why True == "True" Is True in R

Why TRUE == TRUE is TRUE in R?

According to the help file ?`==` :

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.

So TRUE is coerced to "TRUE" (i. e. as.character(TRUE)), hence the equality.

The equivalent of an operator === in some other language (i. e. are the two objects equal and of the same type) would be function identical:

identical(TRUE, "TRUE")
[1] FALSE

What evaluates to True/False in R?

This is documented on ?logical. The pertinent section of which is:

Details:

‘TRUE’ and ‘FALSE’ are reserved words denoting logical constants
in the R language, whereas ‘T’ and ‘F’ are global variables whose
initial values set to these. All four are ‘logical(1)’ vectors.

Logical vectors are coerced to integer vectors in contexts where a
numerical value is required, with ‘TRUE’ being mapped to ‘1L’,
‘FALSE’ to ‘0L’ and ‘NA’ to ‘NA_integer_’.

The second paragraph there explains the behaviour you are seeing, namely 5 == 1L and 5 == 0L respectively, which should both return FALSE, where as 1 == 1L and 0 == 0L should be TRUE for 1 == TRUE and 0 == FALSE respectively. I believe these are not testing what you want them to test; the comparison is on the basis of the numerical representation of TRUE and FALSE in R, i.e. what numeric values they take when coerced to numeric.

However, only TRUE is guaranteed to the be TRUE:

> isTRUE(TRUE)
[1] TRUE
> isTRUE(1)
[1] FALSE
> isTRUE(T)
[1] TRUE
> T <- 2
> isTRUE(T)
[1] FALSE

isTRUE is a wrapper for identical(x, TRUE), and from ?isTRUE we note:

Details:
....

‘isTRUE(x)’ is an abbreviation of ‘identical(TRUE, x)’, and so is
true if and only if ‘x’ is a length-one logical vector whose only
element is ‘TRUE’ and which has no attributes (not even names).

So by the same virtue, only FALSE is guaranteed to be exactly equal to FALSE.

> identical(F, FALSE)
[1] TRUE
> identical(0, FALSE)
[1] FALSE
> F <- "hello"
> identical(F, FALSE)
[1] FALSE

If this concerns you, always use isTRUE() or identical(x, FALSE) to check for equivalence with TRUE and FALSE respectively. == is not doing what you think it is.

Why do I get TRUE when checking if a character value is greater than a number?

The hierarchy for coercion is: logical < integer < numeric < character. So in both cases, the numeric is coerced to character. Characters get "sorted" position by position in ASCII order. So "9" is greater than "2" but "10" is less than "2" because "1" is less than "2".

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

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. .

IF TRUE then Variable name

In base R, an option is to loop over the subset of columns that are logical rowwise, get the first column name based on the logical vector

df$whatIneed <- apply(df[1:3], 1, function(x) names(x)[x][1])
df$whatIneed
[1] "cellphone" "cellphone" NA "cellphone" NA

If we want to do this individually on each column

library(dplyr)
df %>%
mutate(across(where(is.logical),
~ case_when(.x ~ cur_column()), .names = "{.col}_name"))

-output

cellphone money knife whatIneed cellphone_name money_name knife_name
1 TRUE FALSE TRUE cellphone cellphone <NA> knife
2 TRUE FALSE TRUE cellphone cellphone <NA> knife
3 FALSE FALSE FALSE <NA> <NA> <NA>
4 TRUE TRUE FALSE cellphone cellphone money <NA>
5 FALSE FALSE FALSE <NA> <NA> <NA>

Why is the expression 1 ==1 evaluating to TRUE?

From the help("=="):

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.

So 1 should be converted to "1".

all() function gives TRUE but any() gives FALSE for same comparison

From the docs, any ignores zero-length objects:

...

zero or more logical vectors. Other objects of zero length are ignored, and the rest are coerced to logical ignoring any class.

How is this related to NULL == 1?

If we break this down, we see that NULL == 1 returns a logical(0) which is of length 0.

length(logical(0))
[1] 0

This is similar to:

any()
[1] FALSE

Now, why does all work?

The value returned is TRUE if all of the values in x are TRUE (including if there are no values), and FALSE if at least one of the values in x is FALSE. Otherwise the value is NA (which can only occur if na.rm = FALSE and ... contains no FALSE values and at least one NA value).

Note the including if there are no values part.

Compare this to the part in any's doc entry:

The value returned is TRUE if at least one of the values in x is TRUE, and FALSE if all of the values in x are FALSE (including if there are no values)

I think the main point is that since one is comparing NULL with something else, the returned logical vector is empty (i.e. length zero) which affects how the result is dealt with by any/all.

TRUE and FALSE as boolean versus same as characters

To quote ?Comparison in the help files:

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.

R is automatically coercing the values down resulting in

"TRUE" == TRUE
# [1] TRUE
1 == TRUE
# [1] TRUE

etc.

Boolean vector comparison for TRUE/FALSE single results

Similar to all as suggested in the comment by @akrun, one could take the slightly more "backwards" approach of using any, which evaluates to true if at least a one element in a vector is true -- in your example, one element is the same as the standard with respect to its index and value. By evaluating this (input) with !input, meaning NOT input, you can obtain the result you are after.

# Standard
logical.vector = c(TRUE, TRUE, FALSE, TRUE)

# Test Patterns

# Case 1 (non-match): should be FALSE
!any(logical.vector != c(TRUE, FALSE, TRUE, TRUE))

# Case 2 (non-match): should be FALSE
!any(logical.vector != c(FALSE, TRUE, FALSE, TRUE))

# Case 3 (non-match): should be FALSE
!any(logical.vector != c(TRUE, TRUE, TRUE, TRUE))

# Case 4 (non-match): should be FALSE
!any(logical.vector != c(FALSE, FALSE, FALSE, FALSE))

# Case 5 (match): should be TRUE
!any(logical.vector != c(TRUE, TRUE, FALSE, TRUE))


Related Topics



Leave a reply



Submit