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

时间:2013-02-18 01:39:30

标签: r data.table lapply

我在列表中有一堆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)

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

key(blah)

# [1] "a"

但是,如果我将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

这可能与我没有真正理解“通过引用分配键”意味着什么,因为我还有其他问题,键已经消失了。

所以:

  • 为什么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"

但这是R,而for循环是 evil

2 个答案:

答案 0 :(得分:9)

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

lapply(dt.list, unique) 
lapply(dt.list, function(x) unique(x)) 

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


看似意外的行为是由于第一个lapply声明的事实   调用unique.data.frame(即来自{base})而第二个调用unique.data.table

答案 1 :(得分:5)

好问题。事实证明,它记录在?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的方法调度正确发生。