2013-02-10 21 views
12

Ho un po 'di esperienza con gli oggetti S4 e i relativi slot, quindi so come accedere a slot e sotto-slot specifici. Quello che mi piacerebbe imparare è come "de-slotify" un oggetto nel modo in cui unlist separa un elenco S3.
Il mio obiettivo immediato è quello di avere una controparte S4 a uno dei miei giocattoli che restituisce il numero di elementi di un oggetto:Esiste un S4 equivalente a unlist()?

lssize<-function(items){ 
      if (any(sapply(sapply(items,get),typeof)=='closure')){ 
     warning('Closures in list, will ignore.') 
     items<-items[(sapply(sapply(bar,get),typeof)=='closure')!=TRUE] 
    } 
    sizes<-sapply(sapply(sapply(sapply(items,get,simplify=F), unlist,simplify=F), as.vector,simplify=F), length) 
    return(sizes) 
    } 

(senza fiera ridere il mio codice :-)). Spero di non dover scrivere una routine di ricorsione che estrae gli slot uno alla volta per convertirli.

Modifica: so che object.size restituirà il bytecount; non quello che sto cercando qui.

+1

Si potrebbe desiderare di avere uno sguardo a 'str()' ('utils ::: str .default' really) - entrambi i risultati quando applicato a oggetti S4 e il codice che utilizza per percorrere tutti gli slot di un oggetto S4. –

risposta

9

(Viene rivisto per essere più vicino a una risposta eliminata precedente, utilizzando slotName e slot anziché fare affidamento su attributes). Potremmo scrivere una funzione che verifica se un'istanza è un oggetto S4, e se così estrae tutti gli slot come una lista e recurses

f = function(x) { 
    if (isS4(x)) { 
     nms <- slotNames(x) 
     names(nms) <- nms 
     lapply(lapply(nms, slot, object=x), f) 
    } else x 
} 

e poi

A = setClass("A", representation(x="numeric")) 
B = setClass("B", representation(a="A", b="numeric")) 
f(B()) 

per arrivare ad un elenco semplice vecchio che potremmo usare per qualsiasi scopo desideriamo.

$a 
$a$x 
numeric(0) 

$a$class 
[1] "A" 
attr(,"package") 
[1] ".GlobalEnv" 


$b 
numeric(0) 

$class 
[1] "B" 
attr(,"package") 
[1] ".GlobalEnv" 

f potrebbe aver bisogno di essere migliorata, per esempio, per gestire i valori NULL o classi S4 realizzati classi S3 via setOldClass. Il codice a validObject sarebbe la mia scelta di luoghi per cercare un traversal più completo.

Una generalizzazione potrebbe fare un visitatore, lungo le linee di

visitLeavesWith <- 
    function(object, FUN, ...) 
{ 
    f = function(x) { 
     if (isS4(x)) { 
      slots <- setNames(slotNames(x), slotNames(x)) 
      lapply(lapply(slots, slot, object=x), f) 
     } else FUN(x, ...) 
    } 
    f(object) 
} 

ad esempio,

visitLeavesWith(B(), length) 
+0

Questo sembra bello - un buon miglioramento della (rimossa) altra risposta. Sì, probabilmente dovrei "convertire" in dimensioni di reporting di oggetti in byte piuttosto che in conteggi di elementi comunque :-) –

+0

Posso solo sorpassarti una volta :-). Grazie per aver dedicato del tempo a spiffificare il tuo codice. Ti darò pieno credito quando (if) costruirò un pacchetto di strumenti di supporto che include 'lssize'. –

+0

BTW, quindi mi merito il ragazzo giusto - sei il tipo che lavora a Fred H.? –

Problemi correlati