使用 substitute 在 R 表达式中进行变量替换

Using substitute to do variable substitutions inside R expressions

我想使用 substitute() 在表达式中进行变量替换,而不计算表达式。例如,我有:

expr1 <- expression(if(x){
    return(y)
} else {
    return(z)
})

我想做的是将以下结果分配给 "expr1":

expression(if(cos(x)){
    return(y)
} else {
    return(z)
 })

通过这样做:

expr2 <- substitute(expr1, list(x=cos(x)))

但这不起作用,因为 substitute 不计算它的第一个参数。所以我只取回原始变量:

expr1

现在 here 它说要在分配给变量的表达式中进行替换,我必须执行 substitute() 两次,然后是 eval(),如下所示:

expr2 <- eval(substitute(substitute(e, list(x = cos(x))), list(e = expr1)))

当我执行此语句时,我确实得到了一个分配给 "expr2" 的表达式,但它不包含所需的替换:

expression(if (x) {
    return(y)
} else {
    return(z)
})

我可以对 "expr1" 应用什么语法,以便得到我想要分配给 "expr2" 的结果,即:

expression(if (cos(x)) {
    return(y)
} else {
    return(z)
})

这似乎可以解决问题

do.call('substitute', list(expr1[[1]], list(x=quote(cos(x)))))
# if (cos(x)) {
#     return(y)
# } else {
#     return(z)
# }

首先,我使用 do.call 将未计算的表达式作为参数传递给 substitute(),而不是双 substitute。其次,expression() 真的很像一个容器对象。您真正感兴趣的只是更改表达式第一个元素的代码块。您本可以避免 expression() 并使用 quote() 来避免 "unboxing"

expr2 <- quote(if(x){ return(y) } else { return(z) })
do.call('substitute', list(expr2, list(x=quote(cos(x)))))

这两个都将 return 类型为 "if" 的 class。如果需要,可以将其包装在 as.expression().

as.expression(do.call('substitute', list(expr1[[1]], list(x=quote(cos(x))))))
# expression(if (cos(x)) {
#     return(y)
# } else {
#     return(z)
# })

您必须通过将 cos(x) 包装在嵌套 substitution()x = quote() 函数中来添加添加:根据文档,您可以使用 [ 对表达式进行子集化, [[,或 $。您必须在超级替换调用中使用 [[ 对表达式对象进行子集化。试试这个:

expr2 <- eval(substitute(substitute(e, list(x=quote(cos(x)))), list(e = expr1[[1]])))

expr2
#if (cos(x)) {
#  return(y)
#} else {
#  return(z)
#}

要将 expr2 设置为表达式,请调用:as.expression(expr2)

备选方案可能是:

x <- expr(cos(x)) 

expr2 <- expr(if (!!x) {
                return(y)
                 } else {
                 return(z) })