使用R6类包装data.table时,能否自动继承其数据表操作?
让包装data.table的R6类兼容data.table操作的技巧
问题场景
你有一个包装了data.table的R6类,希望直接对该R6对象使用data.table的操作(比如[]子集化),而不需要每次都调用内部的$data字段:
DataTable <- R6Class("DataTable", public = list(data = data.table()) ) tmp_DT <- DataTable$new() tmp_DT$data <- as.data.table( structure(list(x = c(0.546308053890243, 0.0679920904804021, 0.6322269923985, 0.641194123076275, 0.529008251149207, 0.219063043128699, 0.288039632607251, 0.469340555137023, 0.154014938278124, 0.778147601056844)), row.names = c(NA,-10L), class = "data.frame"))
直接调用tmp_DT[x >= 0.5]会报错Error: object 'x' not found,但你希望它等价于tmp_DT$data[x >= 0.5]的结果。
手动解决方案
手动编写对应S3方法,比如[]的方法:
`[.DataTable` <- function(dt, ...) {dt$data[...]} tmp_DT[x >= 0.5] #> x #> <num> #> 1: 0.5463081 #> 2: 0.6322270 #> 3: 0.6411941 #> 4: 0.5290083 #> 5: 0.7781476
但这种方式需要手动编写所有需要的data.table方法,效率很低。
更高效的自动转发技巧
通过注册类继承关系和定义as.data.table转换方法,让S3自动将data.table的方法转发到R6对象内部的data字段:
- 注册类继承:将你的R6类注册为继承自
data.table和data.frame,这样S3方法调度会优先匹配data.table的方法:
setOldClass(c("DataTable", "data.table", "data.frame"))
- 定义转换方法:编写
as.data.table.DataTable方法,返回R6对象内部的data字段:
as.data.table.DataTable <- function(x, ...) { x$data }
完成以上两步后,直接调用data.table的操作就会自动生效:
tmp_DT[x >= 0.5] #> x #> <num> #> 1: 0.5463081 #> 2: 0.6322270 #> 3: 0.6411941 #> 4: 0.5290083 #> 5: 0.7781476 # 其他data.table操作也能直接使用 setkey(tmp_DT, x) tmp_DT[.SD, head(.SD, 3)]
原理是:当调用data.table的方法(比如[.data.table)时,方法内部会先检查输入对象是否为data.table,如果不是,会自动调用as.data.table()转换,而我们定义的as.data.table.DataTable会返回内部的data,从而完成操作的转发。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

