我试图创建一个函数,它将data.table和condition作为输入,然后修改由条件选择的行。当然,我可以明确地将条件定义为逻辑向量,如下所示:
dt1 <- fread(
"id,a,b
id1,1,10
id2,2,30
id3,3,40
")
test1 <- function(dtIn, condition) {
dtIn[condition, newcol:="new text"];
return(dtIn);
}
test1(dt1, dt1$b>10);
但理想情况下,我希望能够在没有表名的情况下通过这个条件,如下所示:
test2 <- function(dtIn, condition) {
dtIn[substitute(condition), newcol:="new text"];
return(dtIn);
}
test2(dt1, b>10);
我尝试了substitute(condition)
,但是它出现错误&#34; i has not evaluated to logical, integer or double
&#34;。是否可以实现所需的功能?
UPD。
正如@Gregor所回答的那样,除了eval
之外,正确的代码只使用了substitute
:
test3 <- function(dtIn, condition) {
dtIn[eval(substitute(condition)), newcol:="new text"];
return(dtIn);
}
我还需要传递列名并在我的函数中构建条件。根据@Gregor的建议,我可以paste
建立条件,然后使用eval(parse(...))
:
test4p <- function(dtIn, colName) {
condition <- parse(text=paste0(colName, ">20"))
dtIn[eval(condition), newcol:="new text"];
return(dtIn);
}
test4p(dt1, "b");
我自己,我采用另一种方法,使用get
:
test4g <- function(dtIn, colName) {
dtIn[get(colName)>20, newcol:="new text"];
return(dtIn);
}
test4g(dt1, "b");
结果是一样的,我没有足够的能力来解释get
和eval(parse(...))
的使用之间的区别,所以欢迎您提出意见。
使用eval(parse(...))
,我能够使函数采用不带引号的列名,即用于调用test4(dt1, b)
(只是将substitute(colName)
添加到代码中),但是没有{{1 }}
答案 0 :(得分:3)
您只是错过了eval()
。
test3 <- function(dtIn, condition) {
dtIn[eval(substitute(condition)), newcol:="new text"];
return(dtIn);
}
> test3(dt1, dt1$b>10);
id a b newcol
1: id1 1 10 NA
2: id2 2 30 new text
3: id3 3 40 new text
即使没有dt1$
> test3(dt1, b>10);
id a b newcol
1: id1 1 10 NA
2: id2 2 30 new text
3: id3 3 40 new text
有关详细说明,请参阅Hadley's Non-Standard Evaluation Section。