【问题标题】:How can you make tidyverse functions that support both quoted and unquoted arguments?如何制作支持带引号和不带引号的参数的 tidyverse 函数?
【发布时间】:2020-08-12 21:29:33
【问题描述】:

我知道如何为名为“变量”的参数{使用dplyr::enquo(variable) 用于未引用的函数参数}或需要您引用参数的函数{使用rlang::sym("variable")}创建支持准引用的函数。有没有一种简单的方法可以使函数同时支持引用和未引用的参数?

例如,dplyr::select() 允许select(mtcars, mpg)select(mtcars, "mpg")。构建可以同时执行的功能的最佳实践是什么?一个考虑因素是对数据屏蔽的影响,我不确定在构建更复杂的函数时是否需要考虑这一点。

我一直在 github 页面中寻找基本的 dplyr 函数,但是像 select 这样的简单函数依赖于一个全新的包 (tidyselect),所以还有很多事情要做。我在 Tidy 评估书中也没有看到明确的解释。下面是一个 hack 函数,它支持带引号和不带引号的参数,但这不是一个可靠的解决方案。我相信有更简单的方法。

library(dplyr)

data(mtcars)

test_func <- function(variable) {
  if(nrow(count(mtcars, {{variable}})) == 1) {
    variable <- rlang::sym(variable)
  }
  count(mtcars, {{variable}})
}

all_equal(
  test_func(cyl),
  test_func("cyl")
)

【问题讨论】:

  • 这种 UI 没有任何用处,因为您无法将字符串保存在变量中并以正常方式引用它。如果您真的想这样做,请按照 akrun 的建议使用 ensym(),它实现的语义与 = 的 LHS 或 library() 函数中的语义相同。
  • 我承认支持这两种类型并不是一个巨大的收获,而且我对这种方法的缺点很感兴趣。 ensym() 会在哪些情况下失败?如果您需要将符号存储为变量(例如在 ggplot 中进行标记),您能否不将符号转换回字符串?
  • 不利的一面是,如果有人看到foo("bar"),他们可能会尝试quux &lt;- "bar"; foo(quux),但他们会感到困惑,因为它不能以相同的方式工作。

标签: r dplyr rlang tidyeval


【解决方案1】:

如果它需要同时处理引用/未引用,请使用ensym

test_func <- function(variable) {  

    dplyr::count(mtcars, !!rlang::ensym(variable))    

  }

-测试

test_func(cyl)
#  cyl  n
#1   4 11
#2   6  7
#3   8 14
test_func('cyl')
#  cyl  n
#1   4 11
#2   6  7
#3   8 14

注意:最好将数据也作为函数的参数

【讨论】:

  • 谢谢!与要求引用或不引用参数相比,这种方法是否存在重大缺点?我之所以问是因为与enquo() 相比,ensym() 在整洁的评估资源中讨论得更少,尽管乍一看ensym() 更通用。
  • @bholly 我认为 enquo 主要是指定的,因为与引用相比,许多人希望将未引用的字符串作为参数传递。有引用,有很多选项。即您可以使用[[[base R 中的列进行子集化,而未引用则需要替换/解析。
  • @bholly,如果这是 n 生产设置,最好有一个汇合页面,您可以在其中指定传递的参数及其期望,这样用户就不会通过引用和未引用
  • 我正计划在函数文档中包含对参数的期望(我正在处理的函数位于私有 repo 的包中)。类似于dplyr::filter()... 参数的tidy-eval cmets。
猜你喜欢
  • 2018-10-08
  • 1970-01-01
  • 2020-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-05
  • 2015-10-29
相关资源
最近更新 更多