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"

На странице справки сказано, что отправка выполняется внутренне следующим образом:

  1. Для каждого аргумента мы получаем список возможного членства в классе из атрибута класса.
  2. Мы проверяем каждый класс по очереди, чтобы увидеть, есть ли подходящий метод.
  3. Если мы найдем подходящий метод, мы убедимся, что он идентичен любому методу, определенному для предыдущих аргументов. Если он идентичен, мы продолжаем, в противном случае мы немедленно переходим к коду по умолчанию.

С 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(...)
  }
}

По сути, мы проверяем, все ли аргументы являются символами. Если это так, мы вызываем нашу символьную функцию. Если нет, мы вызываем реализацию по умолчанию.

Другие вопросы по тегам