Подтвердить что ты не робот

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"), я считаю, что все эти критерии выполнены. Что дает, и как я могу это исправить?

4b9b3361

Ответ 1

attributes("abc")
#NULL

A character вектор не имеет атрибута класса. Я не думаю, что метод может быть отправлен rbind для неявных классов.

Ответ 2

Обходным решением будет определение вашего собственного класса:

b <- "abc"
class(b) <- "mycharacter"
rbind.mycharacter <- function(...) {
   do.call("paste", list(...))
}
rbind(b, b)
# [1] "abc abc"

Причина, по которой она не работает с character, была приятно объяснена Роландом в его комментарии.

Ответ 3

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

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