You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言hashtab适用场景:除任意键外的独特价值探究

R中hashtab的独特优势与对比分析

摘要

R核心团队常因维护负担拒绝功能请求,但hashtab(R>4.2.0)是例外。?hashtab称其可高效关联键与值,目前已有多种实现(hash、r2r、hashmap等),以及environment及其易用扩展(rlang、RC、R6等)。除对象混淆与任意键外,未发现hashtab在其他场景下比其他实现更高效。

技术问询

hashtab除支持任意键外,是否具备独特功能,或在速度、内存、语法方面对某些场景存在切实优势?

已针对hashtab与environment的性能、功能及内部实现展开对比测试:

性能对比测试代码

set.seed(1)
make_hash <- function(n, keys, values) {
    h <- hashtab("identical", n)
    for(i in seq_along(keys)) sethash(h, keys[i], values[[i]])
    h
}
make_env <- function(n, keys, values) setNames(values, keys) |> list2env(size = n)

get_mem <- function(x) as.numeric(lobstr::obj_size(x)) * 0.001
compare <- function(n, keylen) {
    keys <- stringi::stri_rand_strings(n, keylen) 
    values <- sample(list(mapply, iris, 1:1e6, "just a string", 1L), n, replace = TRUE)
    ind <- sample(keys, 1)
    h <- make_hash(n, keys, values)
    e <- make_env(n, keys, values)
    data.frame(
        n = n,
        method = c("environment", "hashtab"),
        make_speed = {
            bench::mark(
                make_env(n, keys, values),
                make_hash(n, keys, values),
                check = F
            )$median |> as.character()
        },
        memory = c(get_mem(e), get_mem(h)),
        access = bench::mark(
            e[[ind]],
            gethash(h, ind, NULL), # the natural h[[ind]] is 2x slower
            iterations = 1e4
        )$median |> as.character()
    )
}

性能基准测试结果

purrr::map_dfr(c(1e2, 1e3, 1e4, 1e5, 1e6), compare, 10)
         n      method make_speed    memory access
1      100 environment     13.8µs     45.11  200ns
2      100     hashtab    139.9µs     41.61    1µs
3     1000 environment    110.5µs    227.56  200ns
4     1000     hashtab     1.25ms    214.34    1µs
5    10000 environment     1.46ms   2041.96  200ns
6    10000     hashtab    13.64ms   2044.10    1µs
7   100000 environment     53.3ms  20185.96  200ns
8   100000     hashtab    394.9ms  19719.11    1µs
9  1000000 environment       2.2s 201625.96  300ns
10 1000000     hashtab       4.1s 192799.18    1µs

引用语义对比

e1 <- new.env()
e1$hi <- 1
e2 <- e1
e2$hi <- 2
e1$hi # 自动补全
#> [1] 2

h1 <- hashtab()
sethash(h1, "hi", 1)
h2 <- h1
sethash(h2, "hi", 2)
gethash(h1, "hi")
#> [1] 2

批量访问对比

e1$bye <- 3
sethash(h1, "bye", 3)

eapply(e1, function(x) x)
#> $hi
#> [1] 2
#> $bye
#> [1] 3
(function(h) {
    val <- list()
    maphash(h, function(k, v) val[[k]] <<- v)
    val
})(h1)
#> $bye
#> [1] 3
#> $hi
#> [1] 2

键名灵活性对比

e1[[iris]] <- 5 # 报错,无法用任意对象作为键...原因何在?
h1[[iris]] <- 5 # 可正常运行

内部实现对比

通过内部检查发现,environment内部包含hashtab:

e <- new.env(size = 2)
e$x <- 5
.Internal(inspect(e))
#> @0x00000226b4083c48 04 ENVSXP g0c0 [REF(5)] <0x00000226b4083c48>
#> ENCLOS:
#>  @0x00000226ac100778 04 ENVSXP g1c0 [MARK,REF(65535),GL,gp=0x8000] #><R_GlobalEnv>
#> HASHTAB:
#>   @0x00000226b5f6b588 19 VECSXP g0c2 [REF(1)] (len=2, tl=1)
#>     @0x00000226b40b0a70 02 LISTSXP g0c0 [REF(1)] 
#>       TAG: @0x00000226aed32ae0 01 SYMSXP g1c0 [MARK,REF(65535)] "x"
#>       @0x00000226b5f3d3a0 14 REALSXP g0c1 [REF(6)] (len=1, tl=0) 5
#>     @0x00000226ac0add90 00 NILSXP g1c0 [MARK,REF(65535)] 

# 注意此处的(len=8)
h <- hashtab(size = 2)
sethash(h, "x", 5)
.Internal(inspect(h))
#> @0x00000226b5f5e8e0 19 VECSXP g0c1 [OBJ,REF(9),ATT] (len=1, tl=0)
#>   @0x00000226b4361ab0 22 EXTPTRSXP g0c0 [REF(3)] <0x00000226b4361ab0>
#>   PROTECTED:
#>     @0x00000226b5f4e898 19 VECSXP g0c4 [REF(1)] (len=8, tl=0)
#>       @0x00000226ac0add90 00 NILSXP g1c0 [MARK,REF(65535)] 
#>       @0x00000226ac0add90 00 NILSXP g1c0 [MARK,REF(65535)] 
#>       @0x00000226ac0add90 00 NILSXP g1c0 [MARK,REF(65535)] 
#>       @0x00000226ac0add90 00 NILSXP g1c0 [MARK,REF(65535)] 
#>       @0x00000226ac0add90 00 NILSXP g1c0 [MARK,REF(65535)] 
#>       ...
#>   TAG:
#>     @0x00000226b235b2e8 13 INTSXP g0c2 [REF(1)] (len=3, tl=0) 1,0,3
#> ATTRIB:
#>   @0x00000226b4361a78 02 LISTSXP g0c0 [REF(1)] 
#>     TAG: @0x00000226ac0ada80 01 SYMSXP g1c0 [MARK,REF(55126),LCK,gp=0x4000] #> "class" (has value)
#>     @0x00000226b5f5e8a8 16 STRSXP g0c1 [REF(65535)] (len=1, tl=0)
#>       @0x00000226b015bb00 09 CHARSXP g1c1 [MARK,REF(320),gp=0x61] [ASCII] #> [cached] "hashtab"

测试包中的异常行为

# devtools::install_github("D-Se/so.hash")
so.hash:::data$hashtab
#> <hashtable (nil): count = 3, type = "identical">
so.hash::grab("x")
#> $env
#> [1] 1
#> 
#> $hash
#> NULL

so.hash:::data$hashtab
#> <hashtable 0x00000168751ebcd0: count = 3, type = "identical">
so.hash::grab("x") # 第二次请求
#> $env
#> [1] 1
#> 
#> $hash
#> [1] 1

对比结论

  • 内存使用相近;
  • 访问速度相近;
  • hashtab创建耗时更长(是否因代码实现问题?);
  • hashtab元素无法在RStudio中自动补全;
  • hashtab键名更灵活;
  • hashtab批量数据访问操作繁琐;
  • hashtab文档极少(仍处于实验阶段);
  • hashtab的size参数未被遵守(?);
  • hashtab存在被PROTECTED的内容¹,但new.env()中无此情况;
  • hashtab存在行为不一致问题。

¹ 不清楚这意味着什么。

内容的提问来源于stack exchange,提问作者Donald Seinen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 12:39:51