Ответ 1
Это действительно ошибка, и она была исправлена в 3.3.1.
Поведение на самом деле немного страннее, чем показывает ваш пример, поскольку вы получаете только FALSE
, когда у вас есть один элемент в левой части %in%
:
> a %in% b
[1] FALSE
> c(a, a) %in% b
[1] TRUE TRUE
Как видно из комментариев, %in%
просто вызывает match
, поэтому проблему можно увидеть и там:
> match(a, b)
[1] NA
> match(c(a, a), b)
[1] 1 1
Важными аргументами %in%
и match
являются x
и table
, где любая функция ищет x
в table
. Под капотом R делает это в функции match5
, определенной в unique.c
. В случае, если у вас более одного x
, match5
создаст хэш-таблицу из table
, чтобы включить быстрый поиск. Если вы копаете код, вы увидите, что сравнение выполняется в функции с именем sequal
, которая возвращает Seql(STRING_ELT(x, i), STRING_ELT(y, j))
(ну, это на самом деле немного сложнее, чем это *). Затем, если вы посмотрите Seql
в memory.c
, вы найдете:
int result = !strcmp(translateCharUTF8(a), translateCharUTF8(b));
Что, как вы можете видеть, преобразует строки в UTF-8.
Однако, если x
имеет только один элемент, глупо идти на проблему создания хеш-таблицы, так как мы можем просто сканировать через table
один раз, чтобы увидеть, есть ли x
. В 3.3.0 код для проверки равенства между x
и каждым элементом table
не использовал Seql
и не преобразовал строку в UTF-8. Но начиная с 3.3.1 используется Seql
, поэтому поведение исправлено.
* Немного в стороне от равенства строк: R фактически кэширует строки, чтобы не было необходимости хранить кучу копий. Поэтому, если две строки находятся в одном и том же месте, они равны, и нет необходимости проверять далее!
> .Internal(inspect("Köln"))
@10321b758 16 STRSXP g0c1 [NAM(2)] (len=1, tl=0)
@106831eb8 09 CHARSXP g1c1 [MARK,gp=0x28,ATT] [UTF8] [cached] "Köln"
> .Internal(inspect(b))
@106831cd8 16 STRSXP g1c1 [MARK,NAM(2)] (len=1, tl=0)
@106831eb8 09 CHARSXP g1c1 [MARK,gp=0x28,ATT] [UTF8] [cached] "Köln"