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

时间:2019-06-05 14:57:05

标签: 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()函数,以便列表内容的摘要实际上是列表内容的直接表示,但是这似乎有些round回。有没有办法告诉tibble使用format()函数而不是obj_sum()格式化我的列表?

1 个答案:

答案 0 :(得分:1)

这最终是了解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产生预期的列条目。