Вопрос
Я написал класс 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».