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 "==" ?

Était-ce utile?

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".

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top