为什么lapply()不保留我的data.table键?

Pau*_*ray 12 r lapply data.table

我在列表中有一堆data.tables.我想应用于unique()我的列表中的每个data.table,但这样做会破坏我的所有data.table键.

这是一个例子:

A <- data.table(a = rep(c("a","b"), each = 3), b = runif(6), key = "a")
B <- data.table(x = runif(6), b = runif(6), key = "x")

blah <- unique(A)
Run Code Online (Sandbox Code Playgroud)

在这里,blah仍然有一把钥匙,世界上的一切都是正确的:

key(blah)

# [1] "a"
Run Code Online (Sandbox Code Playgroud)

但是,如果我将data.tables添加到列表并使用lapply(),则键将被销毁:

dt.list <- list(A, B)

unique.list <- lapply(dt.list, unique) # Keys destroyed here

lapply(unique.list, key) 

# [[1]]
# NULL

# [[2]]
# NULL
Run Code Online (Sandbox Code Playgroud)

这可能与我有关,并没有真正理解"通过引用"分配键意味着什么,因为我有其他问题,密钥消失了.

所以:

  • 为什么lapply不保留我的钥匙?
  • 说"按引用"分配密钥是什么意思?
  • 我是否应该将data.tables存储在列表中?
  • 如何安全地存储/操作data.tables而不用担心丢失我的密钥?

编辑:

对于它的价值,可怕的for循环也可以正常工作:

unique.list <- list()

for (i in 1:length(dt.list)) {
  unique.list[[i]] <- unique(dt.list[[i]])
}

lapply(unique.list, key)

# [[1]]
# [1] "a"

# [[2]]
# [1] "x"
Run Code Online (Sandbox Code Playgroud)

但这是R,for循环是邪恶的.

Ric*_*rta 9

有趣的是,请注意这两种不同结果之间的差异

lapply(dt.list, unique) 
lapply(dt.list, function(x) unique(x)) 
Run Code Online (Sandbox Code Playgroud)

如果您使用后者,结果如您所料.


看似意外的行为是由于第一个lapply语句在第二个语句调用时调用unique.data.frame(即从{base})unique.data.table


Mat*_*wle 6

好问题.事实证明它已记录在案?lapply(参见注释部分):

由于历史原因,lapply创建的调用未被评估,并且代码已经编写(例如bquote)依赖于此.这意味着记录的调用始终为FUN(X [[0L]],...)形式,0L由当前整数索引替换.这通常不是问题,但是如果FUN使用sys.call或match.call,或者它是一个使用该调用的原始函数.这意味着使用包装器调用原始函数通常更安全,因此例如在R 2.7.1中需要lapply(ll,function(x)is.numeric(x))以确保发生is.numeric的方法调度正确.