Есть некоторые конструктивные решения, которые необходимо принять, прежде чем вы сможете привести объекты R6 в кадр данных. Возможно, наиболее важным является то, на каком уровне вы хотите, чтобы происходила векторизация.
В вашем примере у вас есть "atomi c" NumericInterval
s, которые вы помещаете в вектор, и это, безусловно, имеет некоторые преимущества, но главный недостаток заключается в том, что когда вы пытаетесь использовать базовые векторные функции R в наборе NumericInterval
s, R рассматривает объекты как среды (как и R6 объекты). Это означает, что вы не получите то поведение, которое вам нужно, потому что вы хотите, чтобы R обрабатывал вектор этих сред иначе, чем он обычно обрабатывает вектор сред. Другими словами, чтобы справиться с этим способом работы, вам нужно определить другой класс с методами для управления векторными операциями. Это возможно, но кажется сложным, грязным и неэффективным.
Мне кажется, что было бы лучше сохранить векторизацию внутри одного объекта R6, то есть иметь векторы lower_bounds
и upper_bounds
в пределах одного объекта R6. Класс R6 может быть создан для обработки печати, форматирования и поднабора и может действовать как целый столбец в самом фрейме данных.
Чтобы сделать все это, сначала необходимо определить некоторые специализации R6 generi c functions:
`[.R6` <- function(x, ...) x$`[`(...)
`[<-.R6` <- function(x, ...) x$`[<-`(...)
length.R6 <- function(x) x$length()
format.R6 <- function(x) x$format()
as.data.frame.R6 <- function(x, ...) x$as.data.frame()
Имея их как .R6
вместо NumericInterval
, можно использовать их в нескольких разных классах.
Теперь мы можем определить наш класс с нужными нам специализациями :
NumericInterval <- R6Class("NumericInterval",
public = list(
lower_bound = NA,
upper_bound = NA,
initialize = function(low, up) {
self$lower_bound <- low
self$upper_bound <- up
},
`[` = function(n){
return(NumericInterval$new(self$lower_bound[n], self$upper_bound[n]))
},
`[<-` = function(n, m){
self$lower_bound[n] <- m[1]
self$upper_bound[n] <- m[2]
invisible(self)
},
length = function() length(self$lower_bound),
as.data.frame = function(...) {
structure(
list(interval = structure(a)),
class = "data.frame",
row.names = seq_along(self$lower_bound))
},
as_character = function() {
paste0("[", self$lower_bound, ", ",
self$upper_bound, "]")},
format = function(...) self$as_character(),
print = function() {
print(self$as_character(), quote = FALSE)
invisible(self)}))
, который производит следующее поведение:
a <- NumericInterval$new(1:3, 4:6)
a
#> [1] [1, 4] [2, 5] [3, 6]
as.data.frame(a)
#> interval
#> 1 [1, 4]
#> 2 [2, 5]
#> 3 [3, 6]
df <- data.frame(id = LETTERS[1:3], interval = a)
df
#> id interval
#> 1 A [1, 4]
#> 2 B [2, 5]
#> 3 C [3, 6]
df[1,]
#> id interval
#> 1 A [1, 4]
df$interval[1]$lower_bound
#> [1] 1
Это, конечно, не код производственного уровня. В частности, вам нужно будет включить обработку ошибок, чтобы гарантировать, что верхняя и нижняя границы имеют одинаковую длину и оба имеют номера c.