r语言 - 将命名参数传递给调用不变异函数的函数



我正在尝试做一些与这里非常相似的事情。

本质上,我需要将命名列表传递给一个函数,并将该命名列表作为其参数提供给另一个函数。

如果我们按照该链接,他们能够用突变来做到这一点,我可以复制它:

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.callcall的整齐等价物。两者都提供对参数拼接的无缝支持!!!

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"

最新更新