2014-09-27 1 views
5

Angenommen, ich eine Vektor-like S4 Klasse:Warum funktioniert das nicht auf S4-Objekten, die eine as.list.default-Methode haben?

.MyClass <- setClass("MyClass", representation(a="numeric", b="character")) 

setMethod("[", c("MyClass", "numeric", "missing"), function(x, i, j, ...) { 
    do.call(initialize, c(x, sapply(slotNames(x), function(y) slot(x, y)[i], 
      simplify=FALSE))) 
}) 

setMethod("length", "MyClass", function(x) length([email protected])) 

Und sagen, ich habe auch für as.list Methoden definiert und as.list.default:

setGeneric("as.list") 
setMethod("as.list", "MyClass", 
      function(x) lapply(seq_along(x), function(i) x[i])) 
setGeneric("as.list.default") 
setMethod("as.list.default", "MyClass", 
      function(x) lapply(seq_along(x), function(i) x[i])) 

nun ein Objekt dieser Klasse gegeben, myobj:

myobj <- .MyClass(a=1:4, b=letters[1:4]) 

Wenn ich lapply verwende, klagt es:

> lapply(myobj, function(i) rep([email protected], [email protected])) 
Error in as.list.default(X) : 
    no method for coercing this S4 class to a vector 

Aber wenn ich as.list.default verwenden, gibt die Funktion die gewünschte Ausgabe:

> lapply(as.list.default(myobj), function(i) rep([email protected], [email protected])) 
[[1]] 
[1] "a" 

[[2]] 
[1] "b" "b" 
... 

Warum funktioniert lapply nicht, obwohl ich eine Methode für as.list.default für die Klasse definiert haben?

Offensichtlich kann ich manuell eine lapply Methode für die Klasse definieren und es wird gut funktionieren (unten), aber ich frage mich, wo der Fehler tatsächlich angetroffen wird. Warum versucht lapply, mein Objekt in einen Vektor zu zwingen, obwohl die Funktion, die es aufruft, das Objekt in eine Liste verwandeln soll?

setGeneric("lapply") 
setMethod("lapply", c("MyClass", "function"), function(X, FUN, ...) { 
    lapply(as.list(X), FUN, ...) 
}) 
lapply(myobj, function(i) rep([email protected], [email protected])) 
+0

Keine Notwendigkeit, die Generika hier neu zu definieren. Ansonsten sollte der Code wunderbar funktionieren. – agstudy

+0

Ich erstelle normalerweise Generics, so dass ich die 'Creating a generic function for ...' Nachrichten nicht sehe. Ich könnte 'sink' oder' capture.output' verwenden, aber das scheint unsinniger als nur Generika zu definieren. –

Antwort

4

Von der ?Methods Hilfeseite, eine tragfähige Strategie scheint

#same 
.MyClass <- setClass("MyClass", representation(a="numeric", b="character")) 

setMethod("[", c("MyClass", "numeric", "missing"), function(x, i, j, ...) { 
    do.call(initialize, c(x, sapply(slotNames(x), function(y) slot(x, y)[i], 
      simplify=FALSE))) 
}) 

setMethod("length", "MyClass", function(x) length([email protected])) 

#different 
as.list.MyClass <-function(x) { 
    lapply(seq_along(x), function(i) x[i]) 
} 
setMethod("as.list", "MyClass", as.list.MyClass) 

#test 
myobj <- .MyClass(a=1:4, b=letters[1:4]) 
lapply(myobj, function(i) rep([email protected], [email protected])) 

# [[1]] 
# [1] "a" 
# 
# [[2]] 
# [1] "b" "b" 
# 
# [[3]] 
# [1] "c" "c" "c" 
# 
# [[4]] 
# [1] "d" "d" "d" "d" 
+0

Keine Notwendigkeit, 'setMethod' hier zu verwenden. Sie zwingen nur Ihr S4-Objekt mit der generischen S3-Methode as.list. – agstudy

+3

@agstudy Also habe ich die '? Methoden' Hilfeseite falsch interpretiert? oder ist es falsch? (Ich stimme zu, dass es nicht erforderlich ist, 'lapply' zur Arbeit zu bekommen, aber es scheint, als ob es nur eine Best Practice ist.) – MrFlick

+1

ehrlich gesagt habe ich die Hilfe nicht gelesen. Aber es ist eine gute Übung, die S3-Funktion als S4-Methode für Zwang (Wartungsgrund) zu verwenden. Nur meine Bemerkung, um zu zeigen, dass Sie die Frage nicht in genau der S4-Art beantworten, ist eine gute Problemumgehung. – agstudy

Verwandte Themen