Megatron
Megatron

Reputation: 17089

Why are R character and numeric vectors equal in certain contexts?

I've noticed that in R character vectors of numbers are equivalent to their corresponding numeric vectors.

"1234" == 1234
# [1] TRUE
c("1", "2", "3") == 1:3
# [1] TRUE TRUE TRUE
all(c("1", "2", "3") == 1:3)
# [1] TRUE

When using all.equal() we get a message that the modes are different.

all.equal(c("1", "2"), c(1, 2))
# [1] "Modes: character, numeric"               "target is character, current is numeric"

This gets even more complicated when using lists.

myList <- list("1"="a", "2"=c("b", "c"))
myList[c("2", "1")]
# $`2`
# [1] "b" "c"
# 
# $`1`
# [1] "a"

myList[2:1]
# $`2`
# [1] "b" "c"
# 
# $`1`
# [1] "a"

myList[[2]]
# [1] "b" "c"

At this point, one might infer that numeric and character vectors can be used interchangeably when accessing a list. But then...

myList2 <- list("1"="a", "23"=c("b", "c"))
myList2[c(23, 1)]
# $<NA>
# NULL
# 
# $`1`
# [1] "a"

myList2[[23]]
# Error in myList2[[23]] : subscript out of bounds

myList2[["23"]]
# [1] "b" "c"

What is the explanation for this behavior?


R version 3.5.0

Upvotes: 4

Views: 818

Answers (2)

David Klotz
David Klotz

Reputation: 2431

For your examples with list indices, compare the documentation for the base subsetting function: ?`[`

Indices are numeric or character vectors or empty (missing) or NULL. Numeric values are coerced to integer as by as.integer (and hence truncated towards zero). Character vectors will be matched to the names of the object (or for matrices/arrays, the dimnames): see ‘Character indices’ below for further details.

Note this says nothing about integer vectors being coerced to character, as you expect in your question. Your working example succeeds because the list names ('1', '2') match the integer indices. The latter fails because there is no list element with integer index 23.

Upvotes: 1

moodymudskipper
moodymudskipper

Reputation: 47300

Read this recent post : Why does as.numeric(1) == (3 | 4) evaluate to TRUE?

In particular:

coercion rules for comparison operators (?Comparison) tell us that:

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 == '1' is really comparing as.character(1) == '1' which is '1' == '1' which is TRUE.

The other operations you try are not concerned by these coercion rules.

Upvotes: 2

Related Questions