Search code examples
rnon-standard-evaluation

Order by multiple columns using non-standard evaluation


Let's say I want to order a data.frame using multiple columns and using non-standard evolution. I might have a function that looks something like this

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

I get an error when I use this function because my columns are not evaluated within the context of with.

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

NOTE: I do not wish to use dplyr::arrange() for this problem as it adds a dependency.


Solution

  • One option is to wrap the expression into 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
    

    Note that we use eval.parent() instead of eval(), because eval/substitute combo doesn't play well with nested functions. The eval.parent() trick has been proposed by @MoodyMudskipper as a way to address this problem and allows us to seamlessly use my_order() inside other functions, including magrittr pipes:

    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