Search code examples
rdplyrnsenon-standard-evaluation

programming with dplyr::arrange in dplyr v.0.7


I am trying to get my head around the new implementations in dplyr with respect to programming and non standard evaluation. So the verb_ functions are replaced by enquo of the argument and then applying !! in the regular verb function. Translating select from old to new works fine, the following function give similar results:

select_old <- function(x, ...) {
  vars <- as.character(match.call())[-(1:2)]
  x %>% select(vars)
}

select_new <- function(x, ...) {
  vars <- as.character(match.call())[-(1:2)]
  vars_enq <- enquo(vars)
  x %>% select(!!vars_enq)
}

However when I try to use arrange in the new programming style I'll get an error:

arrange_old <- function(x, ...) {
  vars <- as.character(match.call())[-(1:2)]
  x %>% arrange_(vars)
}

arrange_new <- function(x, ...){
  vars <- as.character(match.call())[-(1:2)]
  vars_enq <- enquo(vars)
  x %>% arrange(!!vars_enq)
}

mtcars %>% arrange_new(cyl)     
# Error in arrange_impl(.data, dots) : 
#  incorrect size (1) at position 1, expecting : 32

32 is obviously the number of rows of mtcars, the inner function of dplyr apparently expects a vector of this length. My questions are why does the new programming style not traslate for arrange and how to it then in the new style.


Solution

  • You are overthinking it. Use the appropriate function to deal with .... No need to use match.call at all (also not in the old versions, really).

    arrange_new <- function(x, ...){
      dots <- quos(...)
      x %>% arrange(!!!dots)
    }
    

    Of course this function does the exact same as the normal arrange, but I guess you are just using this as an example.

    You can write a select function in the same way.

    The arrange_old should probably have looked something like:

    arrange_old <- function(x, ...){
      dots <- lazyeval::lazy_dots(...)
      x %>% arrange_(.dots = dots)
    }