|
1 | | -test_that("array2dt works", { |
2 | | - # 测试往返转换 |
3 | | - arr <- array(1:6, |
| 1 | +## helpers --------------------------------------------------------------------- |
| 2 | +make_arr <- function() { |
| 3 | + array(1:6, |
4 | 4 | dim = c(2, 3), |
| 5 | + dimnames = list(site = c("A", "B"), date = c("d1", "d2", "d3")) |
| 6 | + ) |
| 7 | +} |
| 8 | + |
| 9 | +make_arr3 <- function() { |
| 10 | + array(1:24, |
| 11 | + dim = c(2, 3, 4), |
5 | 12 | dimnames = list( |
6 | 13 | site = c("A", "B"), |
7 | | - date = c("d1", "d2", "d3") |
8 | | - # var = c("v1", "v2", "v3", "v4") |
| 14 | + date = c("d1", "d2", "d3"), |
| 15 | + var = paste0("v", 1:4) |
9 | 16 | ) |
10 | 17 | ) |
| 18 | +} |
11 | 19 |
|
12 | | - # array -> dt |
| 20 | +## array2dt -------------------------------------------------------------------- |
| 21 | +test_that("array2dt: 维度列、行数与列名正确", { |
| 22 | + arr <- make_arr() |
13 | 23 | dt <- array2dt(arr, dimnames(arr)) |
| 24 | + |
| 25 | + expect_s3_class(dt, "data.table") |
| 26 | + expect_equal(nrow(dt), prod(dim(arr))) |
| 27 | + expect_equal(names(dt), c("site", "date", "value")) |
| 28 | +}) |
| 29 | + |
| 30 | +test_that("array2dt: 展开顺序为最后一维变化最快 (CJ 顺序)", { |
| 31 | + arr <- make_arr() |
| 32 | + dt <- array2dt(arr, dimnames(arr)) |
| 33 | + |
| 34 | + # 第一维 (site) 变化最慢,最后一维 (date) 变化最快 |
| 35 | + expect_equal(dt$site, rep(c("A", "B"), each = 3)) |
| 36 | + expect_equal(dt$date, rep(c("d1", "d2", "d3"), times = 2)) |
| 37 | + # 值需与 array 下标严格对应 |
14 | 38 | expect_equal(dt[site == "A", value], c(1, 3, 5)) |
| 39 | + expect_equal(dt[site == "B", value], c(2, 4, 6)) |
| 40 | +}) |
| 41 | + |
| 42 | +test_that("array2dt: 支持三维数组", { |
| 43 | + arr <- make_arr3() |
| 44 | + dt <- array2dt(arr, dimnames(arr)) |
| 45 | + |
| 46 | + expect_equal(nrow(dt), 24) |
| 47 | + expect_equal(names(dt), c("site", "date", "var", "value")) |
| 48 | + expect_equal(dt[site == "A" & date == "d1", value], as.vector(arr["A", "d1", ])) |
| 49 | +}) |
| 50 | + |
| 51 | +## dt2array -------------------------------------------------------------------- |
| 52 | +test_that("dt2array: 二维往返转换", { |
| 53 | + arr <- make_arr() |
| 54 | + expect_equal(dt2array(array2dt(arr, dimnames(arr))), arr) |
| 55 | +}) |
| 56 | + |
| 57 | +test_that("dt2array: 三维往返转换", { |
| 58 | + arr <- make_arr3() |
| 59 | + expect_equal(dt2array(array2dt(arr, dimnames(arr))), arr) |
| 60 | +}) |
| 61 | + |
| 62 | +test_that("dt2array: 值的填充不依赖 dt 的行顺序 (回归测试)", { |
| 63 | + arr <- make_arr3() |
| 64 | + dt <- array2dt(arr, dimnames(arr)) |
| 65 | + |
| 66 | + # 维度 level 顺序恰好保持时, 应与原数组完全一致 |
| 67 | + expect_equal(dt2array(dt[order(value)]), arr) |
| 68 | + expect_equal(dt2array(data.table::setkey(data.table::copy(dt), var)), arr) |
| 69 | + |
| 70 | + # 完全打乱行序: level 顺序按首次出现推断, 重排回原顺序后值应一致 |
| 71 | + set.seed(1) |
| 72 | + r <- dt2array(dt[sample(.N)]) |
| 73 | + r <- r[dimnames(arr)$site, dimnames(arr)$date, dimnames(arr)$var] |
| 74 | + expect_equal(r, arr) |
| 75 | +}) |
| 76 | + |
| 77 | +test_that("dt2array: 缺失的维度组合记为 NA", { |
| 78 | + arr <- make_arr() |
| 79 | + dt <- array2dt(arr, dimnames(arr)) |
| 80 | + dt_miss <- dt[!(site == "A" & date == "d2")] |
| 81 | + |
| 82 | + r <- dt2array(dt_miss) |
| 83 | + expect_equal(dim(r), dim(arr)) # 维度不缩减 (其余行仍含全部 level) |
| 84 | + expect_true(is.na(r["A", "d2"])) |
| 85 | + expect_equal(sum(is.na(r)), 1L) |
| 86 | +}) |
| 87 | + |
| 88 | +test_that("dt2array: 保留值的数据类型", { |
| 89 | + # double |
| 90 | + arr_d <- array(c(1.5, 2.5, 3.5, 4.5, 5.5, 6.5), |
| 91 | + dim = c(2, 3), dimnames = list(s = c("A", "B"), d = c("d1", "d2", "d3"))) |
| 92 | + r_d <- dt2array(array2dt(arr_d, dimnames(arr_d))) |
| 93 | + expect_type(r_d, "double") |
| 94 | + expect_equal(r_d, arr_d) |
| 95 | + |
| 96 | + # character |
| 97 | + arr_c <- array(letters[1:6], |
| 98 | + dim = c(2, 3), dimnames = list(s = c("A", "B"), d = c("d1", "d2", "d3"))) |
| 99 | + r_c <- dt2array(array2dt(arr_c, dimnames(arr_c))) |
| 100 | + expect_type(r_c, "character") |
| 101 | + expect_equal(r_c, arr_c) |
| 102 | +}) |
| 103 | + |
| 104 | +test_that("dt2array: 支持非字符维度列 (走 match 分支)", { |
| 105 | + arr <- array(1:6, dim = c(2, 3), |
| 106 | + dimnames = list(id = c(10L, 20L), date = c("d1", "d2", "d3"))) |
| 107 | + dt <- array2dt(arr, dimnames(arr)) |
| 108 | + dt[, id := as.integer(id)] # id 为 integer 列, 由 match 处理 |
| 109 | + |
| 110 | + set.seed(1) |
| 111 | + r <- dt2array(dt[sample(.N)]) |
| 112 | + expect_equal(r[as.character(c(10, 20)), dimnames(arr)$date], arr) |
| 113 | +}) |
| 114 | + |
| 115 | +test_that("dt2array: 支持自定义值列名", { |
| 116 | + arr <- make_arr() |
| 117 | + dt <- array2dt(arr, dimnames(arr)) |
| 118 | + data.table::setnames(dt, "value", "val") |
15 | 119 |
|
16 | | - # dt -> array |
17 | | - arr2 <- dt2array(dt) |
18 | | - expect_equal(arr, arr2) |
| 120 | + expect_equal(dt2array(dt, value_col = "val"), arr) |
19 | 121 | }) |
0 commit comments