Я пытаюсь написать метод для конкатенации двух классов S4, которые я определил:
setClass("My_item",
representation(contents = "vector"))
setClass("My_group",
representation(members = "list"))
members
каждого экземпляра класса My_group
являются членами My_item
class, но я не включил здесь код проверки, который обеспечивает выполнение этого требования.
I wi sh, чтобы написать метод конкатенации для класса My_group
на основе c()
из базы R. Его входные данные будут быть любым числом (включая ноль) элементов, которые могут быть смесью членов класса My_item
или класса My_group
. Метод должен возвращать один член класса My_group
, состоящий из всех My_item
членов на входах, так же, как c(c(1, 2), 3)
возвращает c(1, 2, 3)
.
Я понимаю, что определение моего метода должно точно следуйте определению c()
и поэтому должны принять следующую форму:
setMethod(
f = "c",
signature = "My_group",
definition = function(x, ..., recursive = FALSE) {
[code to be written]
}
)
Мой вопрос касается функции, которая выполняет работу.
Я могу написать прямую функцию R, которая делает то, что я хочу:
myf<- function(...){
elements <- list(...)
if (length(elements) != 0) {
items <- unlist(lapply(
elements,
FUN = function(object) {
if (is(object, "My_group")) {
return(getMy_group(object))
} else {
return(object)
}
}
))
object <- new("My_group",
members = items )
} else {
object <- new("My_group")
}
}
(getMy_group
- это простой метод, который распаковывает члена класса My_group
в список его члены.)
Если я определю a1, a2, a3
как члены класса My_item
, а g1
как My_group
с членами a1
и a2
,
a1 <- new("My_item", contents = c(1, 2, 3))
a2 <- new("My_item", contents = c( "x", "y", "z"))
a3 <- new("My_item", contents = c(0.1, 0.2, 0.3))
g1 <- new("My_group", members = list(a1, a2))
затем myf(g1, a3)
возвращает My_group
с 3 членами, как требуется.
R>str(myf(g1, a3))
Formal class 'My_group' [package ".GlobalEnv"] with 1 slot
..@ members:List of 3
.. ..$ :Formal class 'My_item' [package ".GlobalEnv"] with 1 slot
.. .. .. ..@ contents: num [1:3] 1 2 3
.. ..$ :Formal class 'My_item' [package ".GlobalEnv"] with 1 slot
.. .. .. ..@ contents: chr [1:3] "x" "y" "z"
.. ..$ :Formal class 'My_item' [package ".GlobalEnv"] with 1 slot
.. .. .. ..@ contents: num [1:3] 0.1 0.2 0.3
Но если я определю свой метод, используя тот же код, что и в функции myf
, следующим образом:
setMethod(
f = "c",
signature = "My_group",
definition = function(x, ..., recursive = FALSE) {
elements <- list(...)
if (length(elements) != 0) {
items <- unlist(lapply(
elements,
FUN = function(object) {
if (is(object, "My_group")) {
return(getMy_group(object))
} else {
return(object)
}
}
))
object <- new("My_group",
members = items)
} else {
object <- new("My_group")
}
return(object)
}
)
Я получил неправильный ответ:
R>c(g1, a3)
An object of class "My_group"
Slot "members":
[[1]]
An object of class "My_item"
Slot "contents":
[1] 0.1 0.2 0.3
Метод, похоже, проигнорировал g1
.
Я подозреваю, что неправильно понял роль я, таинственный x
, который появляется в определении c()
, но я не могу получить больше, чем это в моем диагнозе.
Редактировать: следуя полезному и аргументированному предложению JDL, что я использую setClassUnion
Я написал следующее с помощью простого метода, который должен просто возвращать аргументы, переданные c()
.
setClassUnion("mySortOfThing",c("My_item","My_group"))
setMethod(
f = "c",
signature = "mySortOfThing",
definition = function(x, ..., recursive = FALSE) {
elements <- list(...)
return(elements)
}
)
Но я нахожу
g3 <- c(g1, a3)
R>str(g3)
List of 1
$ :Formal class 'My_item' [package ".GlobalEnv"] with 1 slot
.. ..@ contents: num [1:3] 0.1 0.2 0.3
Я, очевидно, все еще ошибаюсь.
Второе редактирование: предложение Алана О'Каллагана решило проблему. Для записи, мой метод теперь:
setMethod(
f = "c",
signature = "My_union",
definition = function(x, ..., recursive = FALSE) {
elements <- list(x, ...)
if (length(elements) != 0) {
items <- unlist(lapply(
elements,
FUN = function(object) {
if (is(object, "My_group")) {
return(getMy_group(object))
} else {
return(object)
}
}
))
object <- new("My_group",
members = items)
} else {
object <- new("My_group")
}
return(object)
}
)
Это дает:
R>c(g1, a3)
An object of class "My_group"
Slot "members":
[[1]]
An object of class "My_item"
Slot "contents":
[1] 1 2 3
[[2]]
An object of class "My_item"
Slot "contents":
[1] "x" "y" "z"
[[3]]
An object of class "My_item"
Slot "contents":
[1] 0.1 0.2 0.3
, что именно то, что я хотел.