base R 将参数的名称替换为函数调用
base R substitute names of the arguments to function call
问题的最终目标是使用r对语言的计算构造以下未评估调用,其中list
,a_name
和 50L
由参数提供。
list(a_name = 50L)
内部看起来像
str(quote(list(a_name = 50L)))
# language list(a_name = 50L)
str(as.list(quote(list(a_name = 50L))))
#List of 2
# $ : symbol list
# $ a_name: int 50
我会将我的变量放在一个列表中,这样以后的代码会更清晰。
params = list(my_fun = as.name("list"), my_name = "a_name", my_value = 50L)
# What I tried so far?
# 1. The first thing that one would try
substitute(my_fun(my_name = my_value),
params)
#list(my_name = 50L) ## `my_name` was not substituted!
# 2. Workaround get the same output, but only after `setNames` call evaluation, so doesn't really answer the question about constructing specific call
substitute(setNames(my_fun(my_value), my_name), ## alternatively could be `structure(..., names=my_name)`
params)
#setNames(list(50L), "a_name")
# 3. Another workaround, not really computing on the language but parsing, and integer L suffix is gone!
with(expr = parse(text=paste0(my_fun, "(", my_name, " = ", my_value, ")"))[[1L]],
data = params)
#list(a_name = 50)
# 4. Working example using rlang
with(expr = rlang::call2(my_fun, !!my_name := my_value),
data = params)
#list(a_name = 50L)
在 base r 中有什么方法可以构建所需的调用吗? 基本上是为了获得与 rlang
完全相同的输出,但使用 base r.
请注意,此问题不是 的重复,后者严格要求 rlang
解决方案。这个问题要求一种使用基 r 来实现它的方法。如果没有办法实现它,我也想知道。谢谢。
假设问题是如何生成一个call
对象,其功能是params
的第一个参数,其单个参数名称是params
的第二个组件的值并且其参数值是 params
的第三个组件,那么 c2
就是那个调用对象。我们验证生成的 cakl 对象与问题中显示的 rlang 调用对象相同。
c2 <- as.call(setNames(params, c("", "", params2$my_name))[-2])
# verify that c2 equals the output of the rlang example in question
c1 <- with(expr = rlang::call2(my_fun, !!my_name := my_value), data = params)
identical(c1, c2)
## [1] TRUE
这概括地说,如果调用有更多参数,使 params 的长度为 n+2,并且 params
的第二个组成部分是长度为 n 的名称向量,那么它仍然有效。
如果您可以控制输入,我认为将输入列表定义为具有函数名称的一个组件和每个参数的一个组件更有意义,组件的名称是参数名称(如反对一个单独的参数来保存名称)。在那种情况下,我们可以简单地编写以下内容。实际上,上面所做的是将参数转换为该形式,然后使用 as.call 所以我们最好从一开始就提供该形式。
as.call(params2) # params2[[1]] is func name, params2[-1] is named args
备注
要执行调用,只需使用:
eval(c2)
或者我们可以使用 do.call
:
do.call(as.character(params[[1]]), setNames(tail(params, -2), params[[2]]))
问题的最终目标是使用r对语言的计算构造以下未评估调用,其中list
,a_name
和 50L
由参数提供。
list(a_name = 50L)
内部看起来像
str(quote(list(a_name = 50L)))
# language list(a_name = 50L)
str(as.list(quote(list(a_name = 50L))))
#List of 2
# $ : symbol list
# $ a_name: int 50
我会将我的变量放在一个列表中,这样以后的代码会更清晰。
params = list(my_fun = as.name("list"), my_name = "a_name", my_value = 50L)
# What I tried so far?
# 1. The first thing that one would try
substitute(my_fun(my_name = my_value),
params)
#list(my_name = 50L) ## `my_name` was not substituted!
# 2. Workaround get the same output, but only after `setNames` call evaluation, so doesn't really answer the question about constructing specific call
substitute(setNames(my_fun(my_value), my_name), ## alternatively could be `structure(..., names=my_name)`
params)
#setNames(list(50L), "a_name")
# 3. Another workaround, not really computing on the language but parsing, and integer L suffix is gone!
with(expr = parse(text=paste0(my_fun, "(", my_name, " = ", my_value, ")"))[[1L]],
data = params)
#list(a_name = 50)
# 4. Working example using rlang
with(expr = rlang::call2(my_fun, !!my_name := my_value),
data = params)
#list(a_name = 50L)
在 base r 中有什么方法可以构建所需的调用吗? 基本上是为了获得与 rlang
完全相同的输出,但使用 base r.
请注意,此问题不是 rlang
解决方案。这个问题要求一种使用基 r 来实现它的方法。如果没有办法实现它,我也想知道。谢谢。
假设问题是如何生成一个call
对象,其功能是params
的第一个参数,其单个参数名称是params
的第二个组件的值并且其参数值是 params
的第三个组件,那么 c2
就是那个调用对象。我们验证生成的 cakl 对象与问题中显示的 rlang 调用对象相同。
c2 <- as.call(setNames(params, c("", "", params2$my_name))[-2])
# verify that c2 equals the output of the rlang example in question
c1 <- with(expr = rlang::call2(my_fun, !!my_name := my_value), data = params)
identical(c1, c2)
## [1] TRUE
这概括地说,如果调用有更多参数,使 params 的长度为 n+2,并且 params
的第二个组成部分是长度为 n 的名称向量,那么它仍然有效。
如果您可以控制输入,我认为将输入列表定义为具有函数名称的一个组件和每个参数的一个组件更有意义,组件的名称是参数名称(如反对一个单独的参数来保存名称)。在那种情况下,我们可以简单地编写以下内容。实际上,上面所做的是将参数转换为该形式,然后使用 as.call 所以我们最好从一开始就提供该形式。
as.call(params2) # params2[[1]] is func name, params2[-1] is named args
备注
要执行调用,只需使用:
eval(c2)
或者我们可以使用 do.call
:
do.call(as.character(params[[1]]), setNames(tail(params, -2), params[[2]]))