S3 диспетчеризация `rbind` и`cbind`
Я пытаюсь написать rbind
метод для определенного класса. Вот простой пример, где это не работает (по крайней мере, для меня):
rbind.character <- function(...) {
do.call("paste", list(...))
}
После входа в эту функцию я, похоже, могу подтвердить, что это правильный метод, о котором R знает:
> methods("rbind")
[1] rbind.character rbind.data.frame rbind.rootogram* rbind.zoo*
see '?methods' for accessing help and source code
Тем не менее, это не признается, если я пытаюсь использовать его:
> rbind("abc", "xyz")
[,1]
[1,] "abc"
[2,] "xyz"
> #### compared with ####
> rbind.character("abc", "xyz")
[1] "abc xyz"
На странице справки сказано, что отправка выполняется внутренне следующим образом:
- Для каждого аргумента мы получаем список возможного членства в классе из атрибута класса.
- Мы проверяем каждый класс по очереди, чтобы увидеть, есть ли подходящий метод.
- Если мы найдем подходящий метод, мы убедимся, что он идентичен любому методу, определенному для предыдущих аргументов. Если он идентичен, мы продолжаем, в противном случае мы немедленно переходим к коду по умолчанию.
С rbind("abc", "xyz")
Я считаю, что все эти критерии выполнены. Что дает, и как я могу это исправить?
3 ответа
attributes("abc")
#NULL
character
вектор не имеет атрибута класса. Я не думаю, что метод может быть отправлен rbind
для неявных классов.
Обходной путь должен был бы определить Ваш собственный класс:
b <- "abc"
class(b) <- "mycharacter"
rbind.mycharacter <- function(...) {
do.call("paste", list(...))
}
rbind(b, b)
# [1] "abc abc"
Причина, почему это не работает с character
был приятно объяснен Роландом в своем комментарии.
rbind
не является стандартной функцией S3, поэтому вы не можете "перехватить" ее для character
,
К счастью, вы можете переопределить реализацию по умолчанию. Пытаться:
rbind.character <- function(...) {
print("hello from rbind.character")
}
rbind <- function(...) {
args <- list(...)
if (all(vapply(args, is.character, logical(1)))) {
rbind.character(...)
} else {
base::rbind(...)
}
}
По сути, мы проверяем, все ли аргументы являются символами. Если это так, мы вызываем нашу символьную функцию. Если нет, мы вызываем реализацию по умолчанию.