卷曲整洁的评估编程,具有多个输入和跨列的自定义函数

los*_*ost 5 r dplyr non-standard-evaluation tidyeval rlang

我的问题与this 问题类似,但我需要跨列应用更复杂的函数,并且我不知道如何将 Lionel 建议的解决方案应用到具有作用域动词 likefilter_at()filter()+across()等价物的自定义函数。{{{}}}看起来并没有引入“superstache”/运算符。

这是我想要做的一个非编程示例(不使用 NSE):

library(dplyr)
library(magrittr)

foo <- tibble(group = c(1,1,2,2,3,3),
              a = c(1,1,0,1,2,2),
              b = c(1,1,2,2,0,1))

foo %>%
  group_by(group) %>%
  filter_at(vars(a,b), any_vars(n_distinct(.) != 1)) %>%
  ungroup
#> # A tibble: 4 x 3
#>   group     a     b
#>   <dbl> <dbl> <dbl>
#> 1     2     0     2
#> 2     2     1     2
#> 3     3     2     0
#> 4     3     2     1
Run Code Online (Sandbox Code Playgroud)

我还没有找到filter_atfilter+相同的行across(),但由于新的 tidyeval 函数早于 dplyr 1.0,我认为这个问题可以放在一边。这是我尝试制作一个编程版本,其中过滤变量是用户提供的点:

my_function <- function(data, ..., by) {
  dots <- enquos(..., .named = TRUE)
  
  helperfunc <- function(arg) {
    return(any_vars(n_distinct(arg) != length(arg)))
  }
  
  dots <- lapply(dots, function(dot) call("helperfunc", dot))
  
  data %>%
    group_by({{ by }}) %>%
    filter(!!!dots) %>%
    ungroup
}

foo %>%
  my_function(a, b, group)
#> Error: Problem with `filter()` input `..1`.
#> x Input `..1` is named.
#> i This usually means that you've used `=` instead of `==`.
#> i Did you mean `a == helperfunc(a)`?
Run Code Online (Sandbox Code Playgroud)

我希望有一种方法可以在vars()参数中插入 NSE 运算符filter_at,而不必进行所有这些额外的调用(我认为这就是函数{{{}}}会做的事情?)

Art*_*lov 4

也许我误解了问题是什么,但转发点的标准模式似乎在这里工作得很好:

my_function <- function(data, ..., by) {
  data %>%
    group_by({{ by }}) %>%
    filter_at(vars(...), any_vars(n_distinct(.) != 1)) %>%
    ungroup
}

foo %>%
  my_function( a, b, by=group )     # works
Run Code Online (Sandbox Code Playgroud)