Frage

Ich habe eine S4-Klasse geschrieben und den „=="-Operator mit überschrieben

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

Wenn ich jetzt testen möchte, ob eine Instanz von CAttribute in einer Liste von CAttributes enthalten ist,

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

Ich erhalte die folgende Fehlermeldung

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

Was mache ich falsch, wie kann ich eine Liste von s4-Objekten auf das Vorkommen eines bestimmten Objekts bzw. eines bestimmten „==“-Operators testen?

War es hilfreich?

Lösung

Wenn Sie nicht überschreiben %in%, wird die aktuelle Implementierung von verwendet %in% dass Sie in der finden können helfen:

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

Der match Funktion erwartet kein Objekt der Klasse CAttribute und das erklärt Ihren Fehler.

Andere Tipps

Um es etwas deutlicher auszudrücken: Wie @Pop betont, erfordert die entsprechende Funktion eine Implementierung.In diesem Fall scheint es so zu sein match ist die relevante Funktion. match muss generisch gemacht werden und den Versand auf relevante Argumente beschränken

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

und dann umgesetzt

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

Ich denke, das würde normalerweise ausreichen, die verwendeten Funktionen match (wie %in%) würde jetzt funktionieren.Aber aus welchem ​​Grund auch immer, es erscheint notwendig, Werbung zu machen %in% zu einem Generikum

setGeneric("%in%")

und das umzusetzen

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

Für das, was es wert ist, verfügt R über „Gruppengenerika“, anstatt nur das zu implementieren == Betreiber wäre es angebracht, z. B. ?Compare

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

was für alle Vergleichsoperatoren gilt, einschließlich ==, verwenden getName() für den Vergleich.

Mit einer grundlegenden Klassendefinition

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

getName <- function(x) x@name

Wir haben

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

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

Beachten Sie, dass die Klasse enthält einen Vektor, der vektorisierte Operationen ermöglicht, die R einigermaßen leistungsfähig machen;Das Definieren einer Skalarklasse und das Erstellen einer Liste davon, wie in der ursprünglichen Frage, ist wahrscheinlich sehr ineffizient.

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

Wenn man eine Liste von Skalaren verwenden würde, müsste man beispielsweise „match,CAttribute,list-method“ implementieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top