如何定义S4类的子集运算符?

Kyl*_*ndt 22 oop r subset s4

我无法找出正确的方式来定义的[,$[[子集运营商的S4类.

任何人都可以为我提供一个为S4类定义这三个的基本示例吗?

Mar*_*gan 37

发现通用,以便我们了解我们的目标

> getGeneric("[")
standardGeneric for "[" defined from package "base"

function (x, i, j, ..., drop = TRUE) 
standardGeneric("[", .Primitive("["))
<bytecode: 0x32e25c8>
<environment: 0x32d7a50>
Methods may be defined for arguments: x, i, j, drop
Use  showMethods("[")  for currently available ones.
Run Code Online (Sandbox Code Playgroud)

定义一个简单的类

setClass("A", representation=representation(slt="numeric"))
Run Code Online (Sandbox Code Playgroud)

并实现一种方法

setMethod("[", c("A", "integer", "missing", "ANY"),
    ## we won't support subsetting on j; dispatching on 'drop' doesn't
    ## make sense (to me), so in rebellion we'll quietly ignore it.
    function(x, i, j, ..., drop=TRUE)
{
    ## less clever: update slot, return instance
    ## x@slt = x@slt[i]
    ## x
    ## clever: by default initialize is a copy constructor, too
    initialize(x, slt=x@slt[i])
})
Run Code Online (Sandbox Code Playgroud)

在行动:

> a = new("A", slt=1:5)
> a[3:1]
An object of class "A"
Slot "slt":
[1] 3 2 1
Run Code Online (Sandbox Code Playgroud)

支持(隐式)许多签名有不同的策略,例如,您可能还希望支持逻辑和字符索引值,可能同时支持i和j.最直接的是"外观"模式,其中每个方法对常见类型的子集索引进行一些初步强制,例如,integer允许重新排序和重复索引条目,然后用于callGeneric调用单个方法对类进行子集化的工作.

[[除了希望尊重返回内容的语义而不是隐含的对象的另一个实例之外,没有概念上的差异[.因为$我们有

> getGeneric("$")
standardGeneric for "$" defined from package "base"

function (x, name) 
standardGeneric("$", .Primitive("$"))
<bytecode: 0x31fce40>
<environment: 0x31f12b8>
Methods may be defined for arguments: x
Use  showMethods("$")  for currently available ones.
Run Code Online (Sandbox Code Playgroud)

setMethod("$", "A",
    function(x, name)
{
    ## 'name' is a character(1)
    slot(x, name)
})
Run Code Online (Sandbox Code Playgroud)

> a$slt
[1] 1 2 3 4 5
Run Code Online (Sandbox Code Playgroud)

  • 谢谢马丁!这真的很有帮助(到了我违反了"不要离开谢谢你评论,因为它是噪音"的规则:-) (9认同)

Liz*_*der 9

我会像@Martin_Morgan建议的那样为你提到的运营商.我会补充几点:

1)我会小心定义一个$操作符来访问S4插槽(除非你打算从存储在特定插槽中的数据帧中访问一列?).一般建议是编写访问器函数getMySlot(),setMySlot()以获取所需的信息.您可以使用@运算符从这些插槽访问数据,尽管get和set最适合作为用户界面.使用$可能会让用户感到困惑,因为用户可能期望使用data.frame.见这个由Christophe Genolini S4教程对这些问题进行了深入的讨论.如果这不是您打算使用的方式$,请忽略我的建议(但该教程仍然是一个很好的资源!).

2)如果你正在定义[[[继承另一个类,比如vector,你也需要定义el()(等同于[][[1L]]或子集中的第一个元素[])和length().我目前正在编写一个继承自数字的类,而数值方法将自动尝试使用您的类中的这些函数.如果课程是为了更有限或个人使用,这可能不是问题.

我道歉,我会留下这个作为评论,但我是新来的SO,我还没有代表!