是否有类似于unlist()的S4等效函数?

12

我有一些使用S4对象及其slot的经验,因此我知道如何访问特定的slot和子slot。我想学习的是如何像unlistS3列表拆开一样“去除”对象中的slot。
我目前的目标是创建一个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会返回字节数; 这里不是我想要的东西。


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

1
你可能想要查看str()(实际上是utils:::str.default) - 无论是应用于S4对象时的结果,还是它用于遍历所有S4对象插槽的代码。 - Josh O'Brien
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值或通过setOldClass从S3类制作的S4类。我选择在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)
}

e.g.,

visitLeavesWith(B(), length)

这看起来不错 - 是对(已删除的)其他答案的很好的改进。是的,我可能应该“转换”为报告对象大小以字节为单位,而不是元素计数 :-) - Carl Witthoft
我只能给你点赞一次 :-) 。感谢您抽出时间整理代码。如果我构建一个包含 lssize 的辅助工具集,我会完全给予您信用。 - Carl Witthoft
顺便说一下,以便归功于正确的人——你是在Fred H.工作的那个家伙吗? - Carl Witthoft
稍晚想到一个问题:对于我的“获取长度”函数,我需要将else FUN(x,...)更改为else length(unlist(x))以覆盖列表对象的可能性。回想起来很明显 :-) - Carl Witthoft

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接