12

我有一些使用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)
    }

(不公平地嘲笑我的代码:-))。我希望不必编写一些递归例程来一次提取一个插槽来转换它们。

编辑:我知道object.size会返回字节数;不是我在这里追求的。

4

1 回答 1

9

(这被修改为更接近以前删除的答案,使用slotNameslot不是依赖attributes)。我们可以编写一个函数来测试一个实例是否是 S4 对象,如果是,则将所有插槽提取为一个列表并递归

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

接着

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

得出一个简单的旧列表,我们可以将其用于我们想要的任何目的。

$a
$a$x
numeric(0)

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


$b
numeric(0)

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

f可能需要增强,例如,处理 NULL 值或通过 S3 类创建的 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)
}

例如,

visitLeavesWith(B(), length)
于 2013-02-11T01:25:59.357 回答