2012-06-09 5 views
17

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

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

ответ

33

Discover родовым, так что мы знаем, что мы нацелены на

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

Спасибо Мартину! Это действительно полезно (до того момента, когда я нарушаю правило «не оставляйте комментарии благодарности, потому что это шум» :-) –

7

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

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

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

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

Смежные вопросы