подкласс класса S4, который содержит список с именами: доступ по имени

Головоломка заключается в доступе к элементам списка в «псевдо-слоте» объекта.

Это успешно с использованием 2 из 4 подходов, которые можно попробовать:

setClass("TempA", contains="list")
A = new("TempA", list(a=1,b=2))
A   

Просто печать A не показывает имена списков.

## An object of class "TempA"
## [[1]]
## [1] 1
## 
## [[2]]
## [1] 2

Тем не менее, вы можете извлечь элементы по имени.

A[["b"]]  
## [1] 2

И names() извлекает имена.

names(A) 
## [1] "a" "b"

А вот имен в псевдослоте нет.

[email protected]  
## [[1]]
## [1] 1
## 
## [[2]]
## [1] 2

Так где же прячутся названия, как не в самом псевдослоте?

Сюжет сгущается. Моя цель - создать подкласс (чтобы добавить несколько слотов, здесь не показано). Но если мы создадим подклассы, даже два успешных подхода, приведенных выше, теперь потерпят неудачу. Фамилий списка, по-видимому, нигде нет.

setClass("TempB", contains="TempA")
B = new("TempB", list(a=1,b=2))
names(B) ## no names.
## NULL
B[["b"]] ## NULL
## NULL

Здесь другой подход. Это делает это? Неа.

B2 = new("TempB", new("TempA", list(a=1,b=2)))
B2[["a"]]  # NULL
## NULL
names(B2) # NULL
## NULL
names(as(B2, "TempA"))  ## still no dice
## NULL

Таким образом, когда псевдо-слот является именованным списком, попытка просмотра или использования этих имен успешна только для 2 из 4 очевидных подходов и ноль из 4 после создания подкласса. Обойти проблему не проблема; это довольно легко. (Хотя я хотел бы знать, как написать средство доступа для объекта TempB, используя имена.) Я просто хочу понять.


person Roger    schedule 21.05.2014    source источник


Ответы (2)


S4 реализует слоты как атрибуты, а R хранит имена элементов списка как атрибут в списке. Таким образом, возникает конфликт, упомянутый в ?Classes. «Решение» состоит в том, чтобы создать класс со слотом «имена».

A = setClass("A", representation("list", names="character"))

но это также требует явного управления именами, например,

setMethod("[", c("A", "ANY", "missing", "missing"),
    function(x, i, j, ..., drop=TRUE)
{
    initialize(x, [email protected][i], names=names(x)[i], ...)
})

Ведущий к

> a = A(list(a=1, b=2))
> a[2:1]
An object of class "A"
[[1]]
[1] 2

[[2]]
[1] 1

Slot "names":
[1] "b" "a"

но и явно неполный

> a[20]
An object of class "A"
[[1]]
NULL

Slot "names":
[1] NA
person Martin Morgan    schedule 21.05.2014

Ах, Мартин, твой ответ привел меня к некоторым открытиям, которые меня удивили! Спасибо. Указание мне посмотреть на экземпляр attributes было ключевым моментом. Я пропустил этот абзац в «Классах».

Ниже показано, что атрибут names списка в слоте .Data передается самому экземпляру:

attributes(A)$names
## [1] "a" "b"

Итак, ВСЕ ли атрибуты перемещаются из слота .Data в экземпляр? Да, в самом деле!

tempList = list(a=3, b=4)
attributes(tempList)$dummy = "dummy"
E = new("TempA", tempList)
attributes(E)$names
## $names
## [1] "a" "b"
## 
attributes(E)$dummy
## $dummy
## [1] "dummy"
attributes([email protected])
## NULL 

Ну, не все атрибуты. Результаты с объектом B2 выше в исходном вопросе показывают, что если элемент .Data сам является экземпляром, его атрибуты не передаются содержащему экземпляру.

Это все еще оставляет открытым вопрос. Конечно, вы не хотите передавать атрибут $class! Но почему бы не перенести все остальные атрибуты?

person Roger    schedule 22.05.2014