Question
J'ai écrit une classe s4 et remplacé l'opérateur "==" avec
setMethod("==",
signature=c(e1="CAttribute", e2="CAttribute"),
definition=function(e1, e2)
{
return(getName(e1) == getName(e2))
}
)
Si je veux maintenant tester si une instance de CAttribute est dans une liste de CAttributes,
a1 <- new("CAttribute", name="a1")
l <- list(new("CAttribute", name="a1"), new("CAttribute", name="a2"))
a1 %in% l
J'obtiens l'erreur suivante
Error in match(x, table, nomatch = 0L) :
'match' requires vector arguments
Qu'est-ce que je fais de mal, comment puis-je tester une liste d'objets s4 pour l'occurrence d'un objet spécifique respectif à un certain opérateur "==" ?
La solution
Si vous ne remplacez pas %in%
, il utilisera l'implémentation actuelle de %in%
que vous pouvez trouver dans le aide:
"%in%" <- function(x, table) match(x, table, nomatch = 0) > 0
Le match
la fonction n'attend pas d'objet de classe CAttribute
et cela explique votre erreur.
Autres conseils
Pour être un peu plus explicite, comme le souligne @Pop, la fonction correspondante nécessite une implémentation.Dans ce cas, il semblerait que match
est la fonction pertinente. match
doit être rendu générique, en limitant l'envoi aux arguments pertinents
setGeneric("match", signature=c("x", "table"))
puis mis en œuvre
setMethod("match", c(x="CAttribute", table="CAttribute"),
function(x, table, nomatch = NA_integer_, incomparables = NULL)
{
match(getName(x), getName(table), nomatch=nomatch,
incomparables=incomparables)
})
Je pense que cela suffirait normalement, les fonctions utilisées match
(comme %in%
) fonctionnerait maintenant.Mais pour une raison quelconque, il semble nécessaire de promouvoir %in%
à un générique
setGeneric("%in%")
et pour mettre en œuvre cela
setMethod("%in%", c("CAttribute", "CAttribute"),
function(x, table)
{
match(x, table, nomatch=0L) > 0L
})
Pour ce que ça vaut, R a des « génériques de groupe », donc plutôt que d'implémenter uniquement le ==
opérateur qu'il serait approprié de mettre en œuvre, par exemple, ?Compare
setMethod("Compare", c(e1="CAttribute", e2="CAttribute"),
definition=function(e1, e2)
{
callGeneric(getName(e1), getName(e2))
})
qui dit pour tous les opérateurs de comparaison, y compris ==
, utiliser getName()
pour la comparaison.
Avec une définition de classe de base
CAttribute <- setClass("CAttribute", representation(name="character"))
getName <- function(x) x@name
Nous avons
CAttribute(name="foo") %in% CAttribute(name=c("foo", "bar"))
## [1] TRUE
CAttribute(name="foo") == CAttribute(name=c("foo", "bar"))
## [1] TRUE FALSE
Notez que le classe contient un vecteur, permettant des opérations vectorisées qui rendent R raisonnablement performant ;définir une classe scalaire et en créer une liste, comme dans la question initiale, sera probablement très inefficace.
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
Si l'on utilisait une liste de scalaires, alors il serait nécessaire d'implémenter, par exemple, "match,CAttribute,list-method".