我正在寻找一种将函数调用包装到另一个函数中的好方法。在一个函数被调用为其他函数之前将其包装是很容易的,但是对我来说修改现有的调用似乎并不那么直接。
我找到了一种方法,可以使用下面的示例进行解释,但是基本上,它依赖于将调用转换为列表并转换为字符串,然后将新调用添加为字符串,然后使用str2lang
将所有内容转换回语言。
是否有一种更清洁的方法?
让我为summarise
构建一个自定义dplyr
函数,该函数将检查输出是否为矢量,在这种情况下,通过在现有调用上使用df-col
创建一个pivot_wider(enframe(...))
。
这里是代表。
library(tidyverse)
short_sum <- function(data, ...) {
fns <- rlang::enquos(...)
fns <- purrr::map(fns, function(x) {
res <- rlang::eval_tidy(x, data = data)
if ((is.vector(res) || is.factor(res)) && length(res) > 1) {
# is there a better way to do this (start) ---
# get expression of call and turn it into a string
x_expr <- as.character(list(rlang::quo_get_expr(x)))
# construct a string with expression above wrapped in another call
x_expr <- paste0(
"pivot_wider(enframe(",
x_expr,
"), names_from = name, values_from = value)"
)
# turn string into language and replace expression in x
x <- rlang::quo_set_expr(x, str2lang(x_expr))
# is there a better way to do this (end) ---
x
} else {
x
}
})
dplyr::summarise(data, !!! fns, .groups="drop")
}
mtcars %>%
as_tibble %>%
short_sum(quant = quantile(mpg),
range = range(wt))
#> # A tibble: 1 x 2
#> quant$`0%` $`25%` $`50%` $`75%` $`100%` range$`1` $`2`
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 10.4 15.4 19.2 22.8 33.9 1.51 5.42
reprex package(v0.3.0)于2020-06-14创建
此问题基于我使用上述方法的答案here。
我不确定100%该功能做什么,但我认为您可能正在寻找类似的东西:
short_sum <- function(data, ...) {
fns <- rlang::enquos(...)
fns <- purrr::map(fns, function(x) {
res <- rlang::eval_tidy(x, data = data)
if ((is.vector(res) || is.factor(res)) && length(res) > 1) {
rlang::expr(pivot_wider(enframe(
!!rlang::quo_get_expr(x)), names_from = name, values_from = value))
# or
# bquote(pivot_wider(enframe(
# .(rlang::quo_get_expr(x))), names_from = name, values_from = value))
} else {
x
}
})
dplyr::summarise(data, !!! fns, .groups="drop")
}
[expr()
类似于quote()
,除了可以使用!!
或!!!
取消对表达式的部分引用。
[bquote()
也类似于quote()
,但在基数R中,您使用.()
取消引用。