我有使用S4对象及其插槽的经验,所以我知道如何访问特定的插槽和子插槽.我想学习的是如何以unlist拆分S3列表的方式对对象进行"去插槽" .
我的直接目标是让我的一个玩具的S4对应物返回一个物体的元素数量:
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)
}
Run Code Online (Sandbox Code Playgroud)
(没有公平地笑我的代码:-)).我希望不必编写一些递归例程,一次提取一个插槽来转换它们.
编辑:我知道object.size会返回bytecount; 不是我在这里.
(这被修改为更接近以前,删除答案,使用slotName和slot而不是依靠attributes).我们可以编写一个测试实例是否是S4对象的函数,如果是,则将所有插槽作为列表提取并进行递归
f = function(x) {
if (isS4(x)) {
nms <- slotNames(x)
names(nms) <- nms
lapply(lapply(nms, slot, object=x), f)
} else x
}
Run Code Online (Sandbox Code Playgroud)
然后
A = setClass("A", representation(x="numeric"))
B = setClass("B", representation(a="A", b="numeric"))
f(B())
Run Code Online (Sandbox Code Playgroud)
到达一个我们可以用于任何我们想要的目的的普通旧列表.
$a
$a$x
numeric(0)
$a$class
[1] "A"
attr(,"package")
[1] ".GlobalEnv"
$b
numeric(0)
$class
[1] "B"
attr(,"package")
[1] ".GlobalEnv"
Run Code Online (Sandbox Code Playgroud)
f可能需要增强,例如,处理由S3类通过的NULL值或S4类setOldClass.代码validObject将是我选择寻找更全面遍历的地方.
概括可能会成为一个访问者,沿着这条线
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)
}
Run Code Online (Sandbox Code Playgroud)
例如,
visitLeavesWith(B(), length)
Run Code Online (Sandbox Code Playgroud)