Pregunta

Escribí una clase s4 y anulé el operador "==" con

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

Si ahora quiero probar si una instancia de CAttribute está en una lista de CAttributes,

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

Obtuve el siguiente error

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

¿Qué hago mal? ¿Cómo puedo probar una lista de objetos s4 para detectar la aparición de un objeto específico respectivo a un determinado operador "=="?

¿Fue útil?

Solución

Si no anulas %in%, utilizará la implementación actual de %in% que puedes encontrar en el ayuda:

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

El match la función no espera un objeto de clase CAttribute y esto explica tu error.

Otros consejos

Para ser un poco más explícito, como señala @Pop, la función relevante requiere implementación.En este caso parecería que match es la función relevante. match necesita ser genérico, restringiendo el envío a argumentos relevantes

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

y luego implementado

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

Creo que esto normalmente sería suficiente, funciones que usaban match (como %in%) ahora funcionaría.Pero por alguna razón, parece necesario promover %in% a un genérico

setGeneric("%in%")

y para implementar eso

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

Por si sirve de algo, R tiene 'genéricos de grupo', por lo que en lugar de implementar solo los == operador sería apropiado implementar, por ejemplo, ?Compare

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

lo que dice para todos los operadores de comparación, incluido ==, usar getName() para la comparación.

Con una definición de clase básica.

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

getName <- function(x) x@name

Tenemos

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

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

Note que el clase contiene un vector, lo que permite operaciones vectorizadas que hacen que R tenga un rendimiento razonable;Es probable que definir una clase escalar y crear una lista de ellas, como en la pregunta original, sea muy ineficiente.

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 uno estuviera usando una lista de escalares, entonces sería necesario implementar, por ejemplo, "coincidencia, atributo CA, método de lista".

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top