R:将列表派生类显示为 tibble 中的向量



我必须经常使用形式为1 + 1i + 1j + 1ij的多维复数(举一个2D示例),我正在尝试定义一个简单的类来促进常见的计算。

在处理多个这样的数字时,我选择使用向量列表表示。但是,我仍然希望这个派生列表类的外观和感觉像一个向量。

我对简单的打印没有问题:

ncmplx <- setClass("ncmplx", contains = "list")
format.ncmplx <- function(x, ...) {
f <- function(y) {
paste(format(as.numeric(y), ...), c('', 'i', 'j', 'ij'), 
sep = '', collapse = '+')
}
unlist(lapply(x, f))
}
setMethod("show", "ncmplx", function(object) {
print(format(object))
})
a <- ncmplx(list(1:4, 2:5))

使用print(a)显示[1] "1+2i+3j+4ij" "2+3i+4j+5ij"这基本上是我想要的。

问题是,如何在tibble中获得类似的显示?我遵循了本指南:https://cran.r-project.org/web/packages/tibble/vignettes/extending.html 但它对所有内容都使用底层向量,而不是列表,这似乎使事情变得更容易。这是我尝试过的:

library(tibble)
pillar_shaft.ncmplx <- function(x, ...) {
out <- format(x)
out[is.na(x)] <- NA
pillar::new_pillar_shaft_simple(out, align = "right")
}
a <- ncmplx(list(1:4, 2:5))
b <- tibble(x = 1:2, a = a)
print(b)

但是结果仍然显示基于列表的表单摘要<int [4]>而不是我想1+2i+3j+4ij的格式。

我可以破解obj_sum()功能,以便我的列表内容的摘要实际上是列表内容的直接表示,但这似乎是迂回的。有没有办法告诉tibble简单地使用format()函数而不是obj_sum()格式化我的列表?

这最终成为了解vctrs包的好机会。简而言之,vctrs使用new_rcrd()函数定义记录样式类。我根据这个小插曲中的说明从上面重新创建了我的基本 2D 复数:https://github.com/r-lib/vctrs/blob/master/vignettes/s3-vector.Rmd

new_cmplx2 <- function(rr = double, ri = double(), ir = double(), ii = double) {
vec_assert(rr, ptype = double())
vec_assert(ri, ptype = double())
vec_assert(ir, ptype = double())
vec_assert(ii, ptype = double())
new_rcrd(list(rr = rr, ri = ri, ir = ir, ii = ii), class = "vctrs_cmplx2")
}
cmplx2 <- function(rr = 0, ri = 0, ir = 0, ii = 0) {
c(rr, ri, ir, ii) %<-% vec_cast_common(rr, ri, ir, ii, .to = double())
c(rr, ri, ir, ii) %<-% vec_recycle_common(rr, ri, ir, ii)
new_cmplx2(rr, ri, ir, ii)
}
format.vctrs_cmplx2 <- function(x, ...) {
rr <- field(x, "rr")
ri <- field(x, "ri")
ir <- field(x, "ir")
ii <- field(x, "ii")
out <- paste0(rr, "+", ri, "i+", ir, "j+", ii, "ij")
out[is.na(rr) | is.na(ri) | is.na(ir) | is.na(ii)] <- NA
out
}
vec_ptype_abbr.vctrs_cmplx2 <- function(x) "cmplx2"
vec_ptype_full.vctrs_cmple2 <- function(x) "complex2d"

由于vctrs是一个整洁的项目,因此与tibble的集成完全符合预期也就不足为奇了:

tibble(x = 1:2, a = cmplx2(rr=1:2))

这将生成a1+0i+0j+0ij, 2+0i+0j+0ij的预期列条目。

最新更新