动态构建查找多列的调用
Dynamically build call for lookup multiple columns
如何使用字符向量变量作为参数动态查找多个字段并通过引用添加。在下面的情况下,我想查找两列并删除其中的 i.
前缀。当然,他们可以覆盖已经存在的同名列。
library(data.table)
set.seed(1)
ID <- data.table(id = 1:3, meta = rep(1,3), key = "id")
JN <- data.table(idd = sample(ID$id, 3, FALSE), value = sample(letters, 3, FALSE), meta = rep(1,3), key = "idd")
select <- c("value","meta") # my fields to lookup
j.lkp <- call(":=", select, lapply(paste0("i.",select), as.symbol))
j.lkp
# `:=`(c("value", "meta"), list(i.value, i.meta))
ID[JN, eval(j.lkp)]
# Error in eval(expr, envir, enclos) : could not find function "i.value"
ID[JN, `:=`(c("value", "meta"), list(i.value, i.meta))]
# id meta value
# 1: 1 1 x
# 2: 2 1 v
# 3: 3 1 f
我知道 similar question 但这个在连接期间要求矢量化参数并直接构建对 j
的调用。
编辑:我知道我可以使用 .SDcols
来完成,但是我无法通过参考
来执行此操作
这是粗略的方法:
myj <- parse(text=paste0("`:=`(",paste0(select,"=i.",select,collapse=","),")"))
ID[JN,eval(myj)]
# id meta value
# 1: 1 1 x
# 2: 2 1 v
# 3: 3 1 f
这对我来说似乎是最直接的方式:
ID[JN, (select) := mget(paste0('i.', select))]
在最近的开发版本中,它变得更加容易
ID[JN, (select) := .list_of_fields,
env=list(.list_of_fields=as.list(paste0('i.', select)))]
1.14.1 之前的旧解决方案
而不是 mget
或 eval-parse
仍然有可能构建查找调用。虽然 mget
对用户最友好,但它既灵活又实际上对应于构建 j
表达式。
包装到 batch.lookup
辅助函数中的解决方案采用列名的字符向量进行查找。
library(data.table)
set.seed(1)
ID <- data.table(id = 1:3, meta = rep(1,3), key = "id")
JN <- data.table(idd = sample(ID$id, 3, FALSE), value = sample(letters, 3, FALSE), meta = rep(1,3), key = "idd")
select <- c("value","meta") # my fields to lookup
batch.lookup = function(x) {
as.call(list(
as.name(":="),
x,
as.call(c(
list(as.name("list")),
sapply(x, function(x) as.name(paste0("i.",x)), simplify=FALSE)
))
))
}
batch.lookup(select)
#`:=`(c("value", "meta"), list(value = i.value, meta = i.meta))
ID[JN, eval(batch.lookup(select))][]
# id meta value
#1: 1 1 x
#2: 2 1 v
#3: 3 1 f
公平地说,这个答案实际上解决了我描述为 OP 的调用构造问题。
如何使用字符向量变量作为参数动态查找多个字段并通过引用添加。在下面的情况下,我想查找两列并删除其中的 i.
前缀。当然,他们可以覆盖已经存在的同名列。
library(data.table)
set.seed(1)
ID <- data.table(id = 1:3, meta = rep(1,3), key = "id")
JN <- data.table(idd = sample(ID$id, 3, FALSE), value = sample(letters, 3, FALSE), meta = rep(1,3), key = "idd")
select <- c("value","meta") # my fields to lookup
j.lkp <- call(":=", select, lapply(paste0("i.",select), as.symbol))
j.lkp
# `:=`(c("value", "meta"), list(i.value, i.meta))
ID[JN, eval(j.lkp)]
# Error in eval(expr, envir, enclos) : could not find function "i.value"
ID[JN, `:=`(c("value", "meta"), list(i.value, i.meta))]
# id meta value
# 1: 1 1 x
# 2: 2 1 v
# 3: 3 1 f
我知道 similar question 但这个在连接期间要求矢量化参数并直接构建对 j
的调用。
编辑:我知道我可以使用 .SDcols
来完成,但是我无法通过参考
这是粗略的方法:
myj <- parse(text=paste0("`:=`(",paste0(select,"=i.",select,collapse=","),")"))
ID[JN,eval(myj)]
# id meta value
# 1: 1 1 x
# 2: 2 1 v
# 3: 3 1 f
这对我来说似乎是最直接的方式:
ID[JN, (select) := mget(paste0('i.', select))]
在最近的开发版本中,它变得更加容易
ID[JN, (select) := .list_of_fields,
env=list(.list_of_fields=as.list(paste0('i.', select)))]
1.14.1 之前的旧解决方案
而不是 mget
或 eval-parse
仍然有可能构建查找调用。虽然 mget
对用户最友好,但它既灵活又实际上对应于构建 j
表达式。
包装到 batch.lookup
辅助函数中的解决方案采用列名的字符向量进行查找。
library(data.table)
set.seed(1)
ID <- data.table(id = 1:3, meta = rep(1,3), key = "id")
JN <- data.table(idd = sample(ID$id, 3, FALSE), value = sample(letters, 3, FALSE), meta = rep(1,3), key = "idd")
select <- c("value","meta") # my fields to lookup
batch.lookup = function(x) {
as.call(list(
as.name(":="),
x,
as.call(c(
list(as.name("list")),
sapply(x, function(x) as.name(paste0("i.",x)), simplify=FALSE)
))
))
}
batch.lookup(select)
#`:=`(c("value", "meta"), list(value = i.value, meta = i.meta))
ID[JN, eval(batch.lookup(select))][]
# id meta value
#1: 1 1 x
#2: 2 1 v
#3: 3 1 f
公平地说,这个答案实际上解决了我描述为 OP 的调用构造问题。