I have some experience working with S4
objects and their slots, so I know how to access specific slots and sub-slots. What I'd like to learn is how to "de-slotify" an object in the way that unlist
takes apart an S3
list.
My immediate goal is to have an S4 counterpart to one of my toys which returns the number of elements of an object:
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)
}
(no fair laughing at my code :-) ). I am hoping not to have to write some recursion routine which extracts slots one at a time to convert them.
Edit: I know object.size
will return the bytecount; not what I'm after here.
(This is revised to be closer to a previous, deleted answer, using slotName
and slot
rather than relying on attributes
). We could write a function that tests whether an instance is an S4 object, and if so extracts all the slots as a list and recurses
f = function(x) {
if (isS4(x)) {
nms <- slotNames(x)
names(nms) <- nms
lapply(lapply(nms, slot, object=x), f)
} else x
}
and then
A = setClass("A", representation(x="numeric"))
B = setClass("B", representation(a="A", b="numeric"))
f(B())
to arrive at a plain old list that we could use for whatever purposes we want.
$a
$a$x
numeric(0)
$a$class
[1] "A"
attr(,"package")
[1] ".GlobalEnv"
$b
numeric(0)
$class
[1] "B"
attr(,"package")
[1] ".GlobalEnv"
f
might need to be enhanced, e.g., to handle NULL values or S4 classes made from S3 classes via setOldClass
. The code to validObject
would be my choice of places to look for a more comprehensive traversal.
A generalization might make a visitor, along the lines of
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)
}
e.g.,
visitLeavesWith(B(), length)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With