data.table的包装函数在本地环境中不起作用

Kun*_*Ren 2 environment r subset data.table

考虑以下功能:

test <- function(x,...) {
  # in practical case, it does more
  x[...]
}
Run Code Online (Sandbox Code Playgroud)

然后调用子集的包装函数在本地环境中不起作用.

> library(data.table)
> m <- data.table(x=1:3,key="x")
> m[J(1)]
   x
1: 1
> local({i <- 1; m[J(i)]})
   x
1: 1
> local({i <- 1; test(m, J(i))})
Error in eval(expr, envir, enclos) : object 'i' not found
> local({i <- 1; test(m, i)})
Error in eval(expr, envir, enclos) : object 'i' not found
Run Code Online (Sandbox Code Playgroud)

这可能是因为test()没有尝试在该环境中查找符号.但是,如果我改data.tabledata.frame和运行的最后一行,它工作正常.

> m <- data.frame(x=1:3)
> local({i <- 1; test(m, i)})
  x
1 1
2 2
3 3
Run Code Online (Sandbox Code Playgroud)

我如何修改test()以便它可以使用...和子集化data.table

我的会话信息:

> sessionInfo()
R version 3.1.1 (2014-07-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252 LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] data.table_1.9.2

loaded via a namespace (and not attached):
[1] plyr_1.8.1    Rcpp_0.11.2   reshape2_1.4  stringr_0.6.2 tools_3.1.1  
Run Code Online (Sandbox Code Playgroud)

MrF*_*ick 5

有意义的是它不起作用,因为[...]for data.table采用在parent.frame中计算的表达式.因此,在这种情况下,J(i)test()在其所在的环境中进行评估.由于test()在全局环境中定义,因此test()默认情况下将在全局环境中搜索未找到的任何变量.该test()功能与您创建的本地环境并不真正相关.您可以test()在其parent.frame中更改要评估的函数.例如

test <- function(x,...) {
    cc <- match.call()
    cc[[1]] <- quote(`[`)
    names(cc)[2]<-"" #make data.frame happy
    eval.parent(cc)
}
Run Code Online (Sandbox Code Playgroud)

测试数据

library(data.table)
m <- data.table(x=1:3,key="x")    
n <- data.frame(x=1:3)
Run Code Online (Sandbox Code Playgroud)

而现在的功能

local({i <- 1; m[J(i)]})
#    x
# 1: 1

local({i <- 1; test(m, J(i))})
#    x
# 1: 1

local({i <- 1; test(n, i)})
#   x
# 1 1
# 2 2
# 3 3

i<-2
test(m, J(i))
#    x
# 1: 2
Run Code Online (Sandbox Code Playgroud)