【问题标题】:How to generate auto-incrementing ID in R如何在 R 中生成自增 ID
【发布时间】:2014-09-18 00:09:35
【问题描述】:

我正在寻找一种有效的方法来为我正在生成的一些合成数据创建唯一的数字 ID。

现在,我只有一个函数,它可以从全局变量中发出和递增一个值(参见下面的演示代码)。但是,这很麻烦,因为我必须初始化 idCounter 变量,并且如果可能的话我宁愿不使用全局变量。

# Emit SSN
idCounter = 0
emitID = function(){
  # Turn into a formatted string
  id = formatC(idCounter,width=9,flag=0,format="d")

  # Increment id counter
  idCounter <<- idCounter+1

  return(id)
}
record$id = emitID()

uuid 包提供了接近我想要的功能,但我需要的 ID 只是整数。有什么建议么?也许是一种将 UUID 值转换为某种数值的方法?显然会发生一些碰撞,但这可能没问题。我认为,我最多需要 10 亿个值。

感谢您的任何建议!

-罗伯

【问题讨论】:

  • 矛盾的要求:“唯一”,“显然会发生一些冲突,但那可能没问题”

标签: r


【解决方案1】:

计数器的非全局版本使用词法作用域将idCounter 与增量函数封装在一起

emitID <- local({
    idCounter <- -1L
    function(){
        idCounter <<- idCounter + 1L                     # increment
        formatC(idCounter, width=9, flag=0, format="d")  # format & return
    }
})

然后

> emitID()
[1] "000000000"
> emitID1()
[1] "000000001"
> idCounter <- 123   ## global variable, not locally scoped idCounter
> emitID()
[1] "000000002"

一个有趣的替代方法是使用“工厂”模式来创建独立的计数器。您的问题意味着您将调用此函数十亿次(嗯,不确定我从哪里得到的印象......),所以通过创建一个 id 缓冲区来矢量化对 formatC 的调用可能是有意义的?

idFactory <- function(buf_n=1000000) {
    curr <- 0L
    last <- -1L
    val <- NULL
    function() {
        if ((curr %% buf_n) == 0L) {
            val <<- formatC(last + seq_len(buf_n), width=9, flag=0, format="d")
            last <<- last + buf_n
            curr <<- 0L
        }
        val[curr <<- curr + 1L]
    }
}
emitID2 <- idFactory()

然后(emitID1 是上述局部变量版本的一个实例)。

> library(microbenchmark)
> microbenchmark(emitID1(), emitID2(), times=100000)
Unit: microseconds
      expr    min     lq median     uq      max neval
 emitID1() 66.363 70.614 72.310 73.603 13753.96 1e+05
 emitID2()  2.240  2.982  4.138  4.676 49593.03 1e+05
> emitID1()
[1] "000100000"
> emitID2()
[1] "000100000"

(原型解决方案比 emitID1 慢约 3 倍,尽管速度不是一切)。

【讨论】:

  • +1 表示local。不要以为我以前从未见过任何人真正使用过它。
  • @BrandonBertelsen 我同意我没有看到它用于此目的,但我在启动脚本中使用了本地。
  • 我以前从未见过本地范围界定 - 非常酷!它正是我想要做的。此外,工厂选项很棒,因为我想生成几组独立的 ID。非常感谢您的帮助:)
  • 想看看这与使用选项存储值相比如何,例如emitID3
【解决方案2】:

我喜欢将proto 包用于小型OO 编程。在底层,它使用环境的方式与 Martin Morgan 说明的方式类似。

# this defines your class
library(proto)
Counter <- proto(idCounter = 0L)
Counter$emitID <- function(self = .) {
   id <- formatC(self$idCounter, width = 9, flag = 0, format = "d")
   self$idCounter <- self$idCounter + 1L
   return(id)
}

# This creates an instance (or you can use `Counter` directly as a singleton)
mycounter <- Counter$proto()

# use it:
mycounter$emitID()
# [1] "000000000"
mycounter$emitID()
# [1] "000000001"

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-14
    • 2016-09-27
    • 2013-04-11
    • 1970-01-01
    • 1970-01-01
    • 2016-03-17
    • 2021-08-06
    • 1970-01-01
    相关资源
    最近更新 更多