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
Rstudio Rmarkdown: Both Portrait and Landscape Layout in a Single PDF
Add Multiple Columns to R Data.Table in One Function Call
Run a for Loop in Parallel in R
Remove Rows from Data Frame Where a Row Matches a String
How to Flatten a List of Lists
Align Ggplot2 Plots Vertically
Reverse Order of Discrete Y Axis in Ggplot2
How to Read Only Lines That Fulfil a Condition from a CSV into R
Proper Idiom for Adding Zero Count Rows in Tidyr/Dplyr
Re-Ordering Factor Levels in Data Frame
How to Create a Loop That Includes Both a Code Chunk and Text with Knitr in R
Rotate a Matrix in R by 90 Degrees Clockwise
Converting a Data Frame to Xts
How to Use Spread on Multiple Columns in Tidyr Similar to Dcast
In R Markdown in Rstudio, How to Prevent the Source Code from Running Off a PDF Page