我正在尝试做一些与这里非常相似的事情。
本质上,我需要将命名列表传递给一个函数,并将该命名列表作为其参数提供给另一个函数。
如果我们按照该链接,他们能够用突变来做到这一点,我可以复制它:
df <- tribble(
~a,
1
)
foo <- function(x, args) {
mutate(x, !!! args)
}
foo(df, quos(b = 2, c = 3)
# A tibble: 1 x 3
a b c
<dbl> <dbl> <dbl>
1 1 2 3
但是,如果我尝试使用任何其他功能执行此操作,则会失败。比如说,如果我尝试使用 print(第一个参数是 x,所以我传递了一个包含 x 的命名列表(:
print(x= "hello")
[1] "hello"
foo <- function(x, args) {
print(!!! args)
}
foo(df, quos(x = "hello"))
Error in !args : invalid argument type
我不确定为什么这在"整洁"功能之外不起作用。我已经尝试了sym,enquo,bang bang,curly curly等的不同组合,但无济于事。
当然,我的最终目标不是使用打印,而是使用另一个用户定义的函数来代替它,所以如果你对如何实现这一目标有任何建议,我也将不胜感激。(顺便说一句,我确实必须使用命名列表,我认为我不能使用......
非常感谢您的帮助。
您可以使用rlang::inject()
:
inject(cbind(!!!letters))
我认为区分文字值(又名常量(和未计算的表达式很重要。例如,无论上下文如何,quos( b=2, c=3 )
的计算结果始终为 2 和 3。在这种情况下,您实际上并不需要这些是 quosure 或表达式,一个简单的值列表就可以了。然后,您可以使用purrr::lift
将任意函数从采用...
点转换为采用列表。无需!!!
:
arglist <- list( replace=TRUE, size=5, x=1:10 ) # Note: list, not quos
sample2 <- purrr::lift(sample)
sample2( arglist ) # Same as sample( x=1:10, size=5, replace=TRUE)
# [1] 7 3 10 8 3
当您想要引用可能尚未定义的变量或列时,未计算的表达式将发挥作用。在这种情况下,您可以利用rlang::list2()
来捕获由!!!
拼接的参数列表:
subset2 <- function( x, ... )
rlang::eval_tidy(rlang::expr(subset( {{x}}, !!!rlang::list2(...) )))
# Capture expressions because mpg and cyl are undefined at this point
argexpr <- rlang::exprs( mpg < 15, select=cyl )
# base::subset() doesn't support !!!, but our new function does!
subset( mtcars, !!!argexpr ) # Error in !argexpr : invalid argument type
subset2( mtcars, !!!argexpr ) # Same as subset( mtcars, mpg < 15, select=cyl )
mtcars %>% subset2(!!!argexpr) # Also works with the pipe
# cyl
# Duster 360 8
# Cadillac Fleetwood 8
# ...
在上面,subset2()
"手动"构造了一个subset( x, arg1, arg2, etc. )
表达式,然后对其进行计算。卷曲运算符用作快捷方式,!!enquo(x)
将用户表达式直接粘贴到最终表达式中,而rlang::list2()
则展开并拼接所有其他参数。通过使用rlang::list2()
而不是base:list()
,我们将对整个函数的!!!
支持添加到整个函数中。
还值得强调的是rlang::exec()
和rlang::call2()
,它们是从基地do.call
和call
的整齐等价物。两者都提供对参数拼接的无缝支持!!!
:
rlang::exec( sample, !!!arglist )
eval(rlang::call2( subset, mtcars, !!!argexpr ))
最后,@Moody_Mudskipper有一个非常好的副词/标签包。其中一个标签将NSE支持添加到任何任意函数,并与%>%
完全集成:
library(tags) ## installed with devtools::install_github("moodymudskipper/tags")
using_bang$sample( !!!arglist )
using_bang$subset( mtcars, !!!argexpr )
mtcars %>% using_bang$subset( !!!argexpr )
您可以在函数中使用match.call()
来获取参数及其名称的列表:
myfun <- function(x, ...){
args <- as.list(match.call())[-1]
print(setNames(unlist(args), names(args)))
lapply(match.call()[-1], class)
}
myfun(x=list(a=1, b="hi", c="a"), b=5)
#> $x
#> list(a = 1, b = "hi", c = "a")
#>
#> $b
#> [1] 5
#> $x
#> [1] "call"
#>
#> $b
#> [1] "numeric"