Вопрос

Я написал класс s4 и переопределил оператор "==" с помощью

setMethod("==",
      signature=c(e1="CAttribute", e2="CAttribute"),
      definition=function(e1, e2)
  {
    return(getName(e1) == getName(e2))
  }
)

Если теперь я хочу проверить, находится ли экземпляр CAttribute в списке CAttribute,

a1 <- new("CAttribute", name="a1")
l <- list(new("CAttribute", name="a1"), new("CAttribute", name="a2"))
a1 %in% l

Я получаю следующую ошибку

Error in match(x, table, nomatch = 0L) : 
  'match' requires vector arguments

Что я делаю не так, как проверить список объектов s4 на наличие конкретного объекта, соответствующего определенному "=="-оператору?

Это было полезно?

Решение

Если вы не переопределите %in%, он будет использовать текущую реализацию %in% которые вы можете найти в помощь:

"%in%" <- function(x, table) match(x, table, nomatch = 0) > 0

А match функция не ожидает объекта класса CAttribute и это объясняет вашу ошибку.

Другие советы

Чтобы быть немного более явным, как указывает @Pop, соответствующая функция требует реализации.В этом случае казалось бы, что match это соответствующая функция. match необходимо сделать общим, ограничивая отправку соответствующими аргументами.

setGeneric("match", signature=c("x", "table"))

а затем реализовал

setMethod("match",  c(x="CAttribute", table="CAttribute"),
    function(x, table, nomatch = NA_integer_, incomparables = NULL)
{
    match(getName(x), getName(table), nomatch=nomatch,
          incomparables=incomparables)
})

Я думаю, этого обычно было бы достаточно, функции, которые использовали match (нравиться %in%) теперь будет работать.Но по какой-то причине кажется необходимым продвигать %in% к общему

setGeneric("%in%")

и реализовать это

setMethod("%in%", c("CAttribute", "CAttribute"),
    function(x, table)
{
    match(x, table, nomatch=0L) > 0L
})

Как бы то ни было, в R есть «групповые обобщения», поэтому вместо реализации только == оператор, который было бы целесообразно реализовать, например, ?Compare

setMethod("Compare", c(e1="CAttribute", e2="CAttribute"),
     definition=function(e1, e2)
{
    callGeneric(getName(e1), getName(e2))
})

что говорит для всех операторов сравнения, включая ==, использовать getName() для сравнения.

С базовым определением класса

CAttribute <- setClass("CAttribute", representation(name="character"))

getName <- function(x) x@name

У нас есть

CAttribute(name="foo") %in% CAttribute(name=c("foo", "bar"))
## [1] TRUE

CAttribute(name="foo") == CAttribute(name=c("foo", "bar"))
## [1]  TRUE FALSE

Обратите внимание, что сорт содержит вектор, позволяющий выполнять векторизованные операции, которые делают R достаточно производительным;определение скалярного класса и создание их списка, как в исходном вопросе, вероятно, будет очень неэффективным.

library(microbenchmark)
microbenchmark(f0=CAttribute(name=rep("A", 1000)),
               f1=replicate(1000, CAttribute(name="A")),
               times=5)
## Unit: microseconds
##  expr       min         lq     median         uq        max neval
##    f0    298.82    306.435    309.681    311.891    334.687     5
##    f1 264214.85 277728.310 286446.876 300839.340 301080.928     5

Если бы кто-то использовал список скаляров, тогда было бы необходимо реализовать, например, «match,CAttribute,list-method».

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top