25

[S4 クラスの、$、および[[サブセット演算子を定義する適切な方法がわかりません。

S4 クラスに対してこれら 3 つを定義する基本的な例を誰か教えてもらえますか?

4

2 に答える 2

40

ジェネリックを発見して、何を目指しているかを理解する

> 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.

単純なクラスを定義する

setClass("A", representation=representation(slt="numeric"))

メソッドを実装する

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])
})

実際に:

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

(暗黙的に) 多くの署名をサポートするためのさまざまな戦略があります。たとえば、おそらく 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.

setMethod("$", "A",
    function(x, name)
{
    ## 'name' is a character(1)
    slot(x, name)
})

> a$slt
[1] 1 2 3 4 5
于 2012-06-09T14:55:26.873 に答える
9

@Martin_Morganがあなたが言及したオペレーターに提案したようにします。ただし、いくつかの点を追加します。

1) S4 スロットにアクセスする演算子を定義する際には注意が必要$です (特定のスロットに格納されているデータ フレームの列にアクセスする場合を除きますか?)。一般的な提案は、次のようなアクセサ関数を記述して、必要な情報getMySlot()setMySlot()取得することです。オペレーターを使用し@てこれらのスロットからデータにアクセスできますが、ユーザー インターフェイスとしては get と set が最適です。使用$すると、おそらく data.frame を期待するユーザーが混乱する可能性があります。これらの問題の詳細については、Christophe Genolini によるこのS4 チュートリアルを参照してください。これが意図した使い方$ではない場合は、私の提案を無視してください (ただし、チュートリアルは依然として優れたリソースです!)。

2) vector のような別のクラスを定義[して継承する場合は、(またはサブセットの最初の要素に相当する) andも定義する必要があります。現在、数値から継承するクラスを作成しています。数値メソッドは、クラスからこれらの関数を自動的に使用しようとします。クラスがより限定された、または個人的な使用のためのものである場合、これは問題にならない可能性があります。[[el()[][[1L]][]length()

申し訳ありませんが、これをコメントとして残しておきますが、私は SO が初めてで、まだ担当者がいません!

于 2012-07-03T15:14:25.027 に答える