R: Вывести производный от списка класс как вектор в таблице - PullRequest
1 голос
/ 05 июня 2019

Мне часто приходится использовать многомерные комплексные числа в форме 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()?

1 Ответ

1 голос
/ 05 июня 2019

Это оказалось хорошей возможностью узнать о пакете vctrs.Вкратце, vctrs определяет класс стиля записи, используя функцию new_rcrd().Я воссоздал свой базовый двумерный комплексный номер сверху на основе инструкций, приведенных в этой виньетке: 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 является проектом Tidyverse, неудивительно, что интеграция с tibble работает точно так же, какпредназначен:

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

Это приводит к ожидаемым столбцам для a: 1+0i+0j+0ij, 2+0i+0j+0ij.

...