Mam problem z ustaleniem właściwego sposobu definiowania operatorów podzbiorów [
, i [[
dla klasy S4.Jak zdefiniować operatorów podzbiorów dla klasy S4?
Czy każdy może podać mi podstawowy przykład zdefiniowania tych trzech dla klasy S4?
Mam problem z ustaleniem właściwego sposobu definiowania operatorów podzbiorów [
, i [[
dla klasy S4.Jak zdefiniować operatorów podzbiorów dla klasy S4?
Czy każdy może podać mi podstawowy przykład zdefiniowania tych trzech dla klasy S4?
Discover rodzajową tak, że wiemy jakie są nasze cele
> 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.
Zdefiniuj prostą klasę
setClass("A", representation=representation(slt="numeric"))
i wdraża metodę
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])
})
w akcji:
> a = new("A", slt=1:5)
> a[3:1]
An object of class "A"
Slot "slt":
[1] 3 2 1
Istnieją różne strategie do obsługi (niejawnie) wielu sygnatur, na przykład prawdopodobnie chcesz również obsługiwać wartości logiczne i wartości indeksu, prawdopodobnie zarówno dla i i j. Najprostszym jest wzór "elewacji", w którym każda metoda dokonuje wstępnego przymusu do wspólnego indeksu podzbioru, np. integer
, aby umożliwić ponowne zamówienie i powtórzenie wpisów indeksu, a następnie wykorzystuje callGeneric
do wywołania pojedynczej metody to działa na podzbiór klasy.
Nie ma żadnych różnic koncepcyjnych dla [[
, poza tym, że chce szanować semantykę zwracania treści, a nie inną instancję obiektu, co sugeruje [
. Dla $
mamy
> 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.
i
setMethod("$", "A",
function(x, name)
{
## 'name' is a character(1)
slot(x, name)
})
z
> a$slt
[1] 1 2 3 4 5
chciałbym zrobić jak @Martin_Morgan sugerowane dla operatorów pan wspomniał. Dodałbym jednak kilka punktów:
1) Byłbym ostrożny w definiowaniu operatora $
, aby uzyskać dostęp do slotu S4 (chyba że zamierzasz uzyskać dostęp do kolumny z ramki danych, która jest przechowywana w konkretnym gnieździe?) . Ogólną sugestią jest napisanie funkcji akcesora, takich jak getMySlot()
i setMySlot()
, aby uzyskać potrzebne informacje. Możesz użyć operatora @
, aby uzyskać dostęp do danych z tych gniazd, chociaż ustawienie get i set są najlepsze jako interfejs użytkownika. Używanie $
może być mylące dla użytkownika, który prawdopodobnie oczekiwałby danych.frame. Poradnik na ten temat znajduje się w samouczku Christophe'a Genoliniego z this S4. Jeśli to nie jest sposób, w jaki zamierzałeś użyć $
, zignoruj moją sugestię (ale samouczek wciąż jest świetnym źródłem!).
2) Jeśli definiujesz [
i [[
dziedziczyć z innej klasy, jak wektor, chcemy też, aby określić el()
(Odpowiednik [][[1L]]
lub pierwszego elementu z podzbioru []
) i length()
. Obecnie piszę klasę, która dziedziczy po numerycznej, a metody numeryczne automatycznie spróbują użyć tych funkcji ze swojej klasy. Jeśli zajęcia są dla bardziej ograniczonego lub osobistego użytku, nie może to stanowić problemu.
Przepraszam, zostawiłbym to jako komentarz, ale jestem nowy w SO i nie mam jeszcze rep!
Dzięki Martin! Jest to bardzo pomocne (do tego stopnia, że naruszam zasadę "nie zostawiajcie podziękowań, ponieważ to jest hałas" :-) –