R:从向量传递命名函数参数

R: Passing named function arguments from vector

我怎样才能实现从命名向量传递命名函数参数?

vec <- c(b=5, a=3)
fun <- function(a, b) {
  browser()
  message(sprintf("a=%s", a))
  message(sprintf("b=%s", b))
}
fun(vec) # should return a=3, b=5

我的意思是在这个例子中,我想动态地将值从 vec 传递到 fun 而无需执行 a=vec$ab=vec$b?

你是这个意思吗?

vec <- c(b=5, a=3)
fun <- function(v) {
  browser()
  message(sprintf("a=%s", v['a']))
  message(sprintf("b=%s", v['b']))
}
fun(vec) # should return a=3, b=5

输出:

> fun(vec) # should return a=3, b=5
Called from: fun(vec)
Browse[1]> 
debug at #3: message(sprintf("a=%s", v["a"]))
Browse[2]> 
a=3
debug at #4: message(sprintf("b=%s", v["b"]))
Browse[2]> 
b=5
> 

在 R 中有几种方法可以做到这一点,但通常您需要将命名的 vector 转换为命名的 list在某些时候使用 as.list

例如使用with

with(as.list(vec), {
  fun(a, b)
})
#> a=3
#> b=5

do.call

do.call(fun, as.list(vec))
#> a=3
#> b=5

如果您经常使用该函数并希望避免样板文件,另一种选择是使用包装函数,只需传递 vec

即可轻松调用
f <- function(v) eval(as.call(c(quote(fun), as.list(v))))

f(vec)
#> a=3
#> b=5

注意 $ 不能用于子集命名向量,所以你不能 evenfun(a = vec$a, b = vec$b) ;你需要做 fun(a = vec['a'], b = vec['b'])。使用 $ 需要 listdata.frameenvironment

在基础 R 中,我们可以将 eval(bquote())..()splice = TRUE 一起使用。

在 {rlang} 中,我们可以使用 inject 代替 !!!

替代现有的 do.call() 答案(见上文){rlang} 有 exec() 它也采用原子向量而不是列表。

vec <- c(b = 5,  a = 3)

fun <- function(a, b) {
  message(sprintf("a=%s", a))
  message(sprintf("b=%s", b))
}

# base R
eval(bquote(fun(..(vec)), splice = TRUE)) 
#> a=3
#> b=5

# rlang
rlang::inject(fun(!!! vec))
#> a=3
#> b=5

# rlang
rlang::exec(fun, !!! vec)
#> a=3
#> b=5

reprex package (v2.0.1)

于 2022-04-28 创建