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