使用非标准评估按多列排序

Order by multiple columns using non-standard evaluation

假设我想使用多列并使用非标准进化来订购 data.frame。我可能有一个看起来像这样的函数

my_order <- function(data, ...) {
  with(data, order(...))
}

我在使用此函数时遇到错误,因为我的列未在 with 的上下文中计算。

my_order(mtcars, mpg, cyl)
# Error in order(...) : object 'mpg' not found 

注意:我不希望使用 dplyr::arrange() 来解决这个问题,因为它增加了依赖性。

这是使用基数 R 传递未解析符号的一种方法

my_order <- function(data, ...) {
  dots <- substitute(...())
  with(data, do.call("order", as.list(dots)))
}
my_order(mtcars, mpg, cyl)

基本上我们使用 substitute 来捕获符号名称,然后使用 do.call 将它们注入到对 order.

的调用中

或者您可以考虑重新编写对函数的调用并更改评估环境

my_order <- function(data, ...) {
  call <-match.call()
  call[[1]] <- quote(order)
  call[2] <- NULL
  eval(call, data, parent.frame())
}
my_order(mtcars, mpg, cyl)

一个选项是将表达式包装成 eval.parent(substitute(...)):

my_order <- function( data, ... ) {
  eval.parent(substitute( with(data, order(...)) ))
}

my_order( mtcars, cyl, mpg )
# [1] 32 21  3  9  8 27 26 19 28 18 20 11  6 10 30  1  2  4 15 16 24  7 17 31 14
# [26] 23 22 29 12 13  5 25

请注意,我们使用 eval.parent() 而不是 eval(),因为 . The eval.parent() trick has been 是解决此问题的一种方式,并允许我们在其他函数中无缝使用 my_order(),包括 magrittr 管道:

mtcars %>% my_order(cyl)
# [1]  3  8  9 18 19 20 21 26 27 28 32  1  2  4  6 10 11 30  5  7 12 13 14 15 16
# [26] 17 22 23 24 25 29 31