3

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

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

使用此函数时出现错误,因为我的列未在with.

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

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

4

2 回答 2

4

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

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

基本上我们使用替代来捕获符号名称,然后使用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)
于 2019-11-07T21:53:28.887 回答
4

一种选择是将表达式包装成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(),因为eval/substitute 组合不能很好地与嵌套函数一起使用@MoodyMudskipper 提出了这个eval.parent()技巧来解决这个问题,并允许我们在其他函数中无缝使用,包括 magrittr 管道:my_order()

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
于 2019-11-07T21:56:41.297 回答