Как определить операторы подмножества для класса S4?

18

У меня возникли проблемы с определением правильного способа определения операторов [ , $ и [[ для класса S4.

Может ли кто-нибудь предоставить мне базовый пример определения этих трех для класса S4?

    
задан Kyle Brandt 09.06.2012 в 16:33
источник

2 ответа

34

Обнаружьте общий, чтобы мы знали, к чему мы стремимся

> 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
    ## [email protected] = [email protected][i]
    ## x
    ## clever: by default initialize is a copy constructor, too
    initialize(x, [email protected][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
    
ответ дан Martin Morgan 09.06.2012 в 16:55
источник
  • Спасибо Мартину! Это действительно полезно (до того момента, когда я нарушаю правило «не оставляйте комментарии благодарности, потому что это шум» :-) –  Kyle Brandt 09.06.2012 в 19:11
8

Я бы сделал так, как предложил @Martin_Morgan для упомянутых вами операторов. Я бы добавил пару пунктов, хотя:

1) Я был бы осторожен в определении оператора $ для доступа к слоту S4 (если вы не собираетесь обращаться к столбцу из фрейма данных, который хранится в определенном слоте?). Общее предложение состоит в том, чтобы написать функции доступа, такие как getMySlot() и setMySlot() , для получения необходимой вам информации. Вы можете использовать оператор @ для доступа к данным из этих слотов, хотя get и set лучше всего использовать в качестве пользовательского интерфейса. Использование $ может ввести в заблуждение пользователя, который, вероятно, ожидал бы data.frame. См. этот учебник S4 от Christophe Genolini для углубленного обсуждения этих вопросов , Если вы не собираетесь использовать $ , пренебрегайте моим предложением (но учебник по-прежнему остается отличным ресурсом!).

2) Если вы определяете [ и [[ для наследования другого класса, например вектора, вы также захотите определить el() (эквивалентно [][[1L]] или первый элемент из подмножества [] ) и length() . В настоящее время я пишу класс для наследования из числа, а числовые методы будут автоматически пытаться использовать эти функции из вашего класса. Если класс предназначен для более ограниченного или личного использования, это может не быть проблемой.

Я прошу прощения, я бы оставил это в качестве комментария, но я новичок в SO, и у меня пока нет репутации!

    
ответ дан Liz Sander 03.07.2012 в 17:14
источник