用多个值替换表达式中的一个符号
Replace one symbol in an expression with multiple values
给定任意固定表达式,我想用多个值的集合替换单个符号。示例:
Expression | Symbol | Replace with | Desired Output
-----------------------------------------------------------------------------------------
f(x, 5) | x | a = 1, b = sym, c = "char" | f(a = 1, b = sym, c = "char", 5)
g(f(h(y)), z) | y | 1, 2, 3 | g(f(h(1, 2, 3)), z)
g(f(h(y), z), z) | z | 4, x | g(f(h(y), 4, x), 4, x)
substitute()
函数很接近,但这并不是我要找的。在下面的例子中,我想把 f(x)
变成 f(1, b = 4, c = d)
,但是我还没有找到正确的 env
参数。
substitute(
expr = f(x),
env = list(x = list(1, b = 4, c = rlang::sym("d")))
)
#> f(list(1, b = 4, c = d))
substitute(
expr = f(x),
env = list(x = as.call(c(quote(x), 1, b = 4, c = quote(d)))[-1])
)
#> f(1(b = 4, c = d))
由 reprex package (v0.2.1)
于 2019-02-09 创建
是否可以找到 env
使得 substitute(f(x), env)
等于 f(1, b = 4, c = d)
?
备注:
- 以上,重要的是我们从
f(x)
开始。我们不能简单地写 as.call(c(quote(f), env))
.
- 在 https://github.com/ropensci/drake/issues/724 and https://github.com/ropensci/drake/issues/726 中描述了激励用例。
- 我们不能使用 tidy evaluation 中的
!!!
,因为 drake
中的所有 tidy evaluation 都需要单独处理。
- 这个 post 替换了不太清楚的 an earlier one。
这个答案很笨拙,但(我认为)它可以满足您的需求;它受到 的启发(以及从中摘录的一行)到某种相关的 post:
multi_substitute <- function(expr, key, ...) {
expr <- deparse(substitute(expr))
key <- deparse(substitute(key))
# The following line is the bit I got from the mentioned SO answer
l <- sapply( substitute(list(...)), deparse)[-1]
l <- paste(names(l), l, sep = " = ")
l <- sub("^ = ", "", l)
l <- paste(l, collapse = ",")
vals <- deparse(substitute(...))
result <- sub(key, l, expr)
return(parse(text = result)[[1]])
}
multi_substitute(f(x), x, 1, b = 4, c = quote(d))
# f(1, b = 4, c = quote(d))
您可以让它更优雅一点或对其进行调整以更好地满足您的需求。
如果您不想在那里强制提供 key
参数,您当然可以很容易地改变它。
这里有一个拼接函数
splice <- function(x, replacements) {
if (is(x, "call")) {
as.call(do.call("c",lapply(as.list(x), splice, replacements), quote=T))
} else if (is(x, "name")) {
if (deparse(x) %in% names(replacements)) {
return(replacements[[deparse(x)]])
} else {
list(x)
}
} else {
list(x)
}
}
它似乎适用于样本输入
splice(quote(f(x, 5) ), list(x=list(a = 1, b = quote(sym), c = "char" )))
# f(a = 1, b = sym, c = "char", 5)
splice(quote(g(f(h(y)), z)) , list(y=list(1,2,3)))
# g(f(h(1, 2, 3)), z)
splice(quote(g(f(h(y), z), z)), list(z=list(4, quote(x))) )
# g(f(h(y), 4, x), 4, x)
基本上你只是换掉符号名称。它也应该适用于不在列表中的单个变量替换。
splice(quote(f(x,5)), list(x=7))
# f(7, 5)
您基本上需要通过将其作为列表进行操作来重新编写调用。这就是 tidyverse 函数在幕后所做的事情。他们拦截当前的调用,重写它,然后评估新扩展的调用。 substitute
永远不会起作用,因为您不仅仅是用一个值替换一个符号。您需要更改传递给函数的参数数量。
给定任意固定表达式,我想用多个值的集合替换单个符号。示例:
Expression | Symbol | Replace with | Desired Output
-----------------------------------------------------------------------------------------
f(x, 5) | x | a = 1, b = sym, c = "char" | f(a = 1, b = sym, c = "char", 5)
g(f(h(y)), z) | y | 1, 2, 3 | g(f(h(1, 2, 3)), z)
g(f(h(y), z), z) | z | 4, x | g(f(h(y), 4, x), 4, x)
substitute()
函数很接近,但这并不是我要找的。在下面的例子中,我想把 f(x)
变成 f(1, b = 4, c = d)
,但是我还没有找到正确的 env
参数。
substitute(
expr = f(x),
env = list(x = list(1, b = 4, c = rlang::sym("d")))
)
#> f(list(1, b = 4, c = d))
substitute(
expr = f(x),
env = list(x = as.call(c(quote(x), 1, b = 4, c = quote(d)))[-1])
)
#> f(1(b = 4, c = d))
由 reprex package (v0.2.1)
于 2019-02-09 创建是否可以找到 env
使得 substitute(f(x), env)
等于 f(1, b = 4, c = d)
?
备注:
- 以上,重要的是我们从
f(x)
开始。我们不能简单地写as.call(c(quote(f), env))
. - 在 https://github.com/ropensci/drake/issues/724 and https://github.com/ropensci/drake/issues/726 中描述了激励用例。
- 我们不能使用 tidy evaluation 中的
!!!
,因为drake
中的所有 tidy evaluation 都需要单独处理。 - 这个 post 替换了不太清楚的 an earlier one。
这个答案很笨拙,但(我认为)它可以满足您的需求;它受到
multi_substitute <- function(expr, key, ...) {
expr <- deparse(substitute(expr))
key <- deparse(substitute(key))
# The following line is the bit I got from the mentioned SO answer
l <- sapply( substitute(list(...)), deparse)[-1]
l <- paste(names(l), l, sep = " = ")
l <- sub("^ = ", "", l)
l <- paste(l, collapse = ",")
vals <- deparse(substitute(...))
result <- sub(key, l, expr)
return(parse(text = result)[[1]])
}
multi_substitute(f(x), x, 1, b = 4, c = quote(d))
# f(1, b = 4, c = quote(d))
您可以让它更优雅一点或对其进行调整以更好地满足您的需求。
如果您不想在那里强制提供 key
参数,您当然可以很容易地改变它。
这里有一个拼接函数
splice <- function(x, replacements) {
if (is(x, "call")) {
as.call(do.call("c",lapply(as.list(x), splice, replacements), quote=T))
} else if (is(x, "name")) {
if (deparse(x) %in% names(replacements)) {
return(replacements[[deparse(x)]])
} else {
list(x)
}
} else {
list(x)
}
}
它似乎适用于样本输入
splice(quote(f(x, 5) ), list(x=list(a = 1, b = quote(sym), c = "char" )))
# f(a = 1, b = sym, c = "char", 5)
splice(quote(g(f(h(y)), z)) , list(y=list(1,2,3)))
# g(f(h(1, 2, 3)), z)
splice(quote(g(f(h(y), z), z)), list(z=list(4, quote(x))) )
# g(f(h(y), 4, x), 4, x)
基本上你只是换掉符号名称。它也应该适用于不在列表中的单个变量替换。
splice(quote(f(x,5)), list(x=7))
# f(7, 5)
您基本上需要通过将其作为列表进行操作来重新编写调用。这就是 tidyverse 函数在幕后所做的事情。他们拦截当前的调用,重写它,然后评估新扩展的调用。 substitute
永远不会起作用,因为您不仅仅是用一个值替换一个符号。您需要更改传递给函数的参数数量。