0

I am currently working my way through the topics on expressions and quasiquotation in the 2nd edition of Hadley's Advanced R book. In the exercise section 20.6.5 the task is to

"Implement arrange_desc(), a variant of dplyr::arrange() that sorts in descending order by default."

When playing around I noticed some things that puzzle me. First, I simply tried to write a function that will take a data frame and variables by which to order as an input. I wanted to automatically quote the variables to mirror dplyr::arrange()'s behaviour

arrange_desc2 <- function(.data, ...) {
   my_args <- enexprs(...)
   new_order <- order(.data[[my_args[[1]]]])
   return(list(my_args = my_args, new_order = new_order))
}

df <- data.frame(a = c(4, 3, 2, 1), 
                 b = c('d', 'c', 'b', 'a'))

arrange_desc2(df, a)

# $my_args
# $my_args[[1]]
# a

# $new_order
# [1] 4 3 2 1

This works, but frankly, I do not understand why: after all, I am subsetting with a symbol here. Digging deeper, I noticed that if I write the code like this, I get an error:

arrange_desc3 <- function(.data, ...) {
   my_args <- enexprs(...)
   new_order <- order(.data[, my_args[[1]]])
   return(list(my_args = my_args, new_order = new_order))
}

arrange_desc3(df, a)
# Error in .subset(x, j) : invalid subscript type 'symbol'

Why can I subset a list with a symbol (is it the same as an expression here?) and why is the symbol apparently evaluated using the list as an environment but only when using [[, not when using [? Put differently, what is the difference between:

a <- c(1, 1, 4, 3)
a[a]
# [1] 1 1 3 4
a[sym("a")] # but list(a = a)[[sym("a")]] will work!
# Error in a[sym("a")] : invalid subscript type 'symbol'
FloHu
  • 1
  • 3

1 Answers1

0

If we are converting to symbol, then evaluate it

a[eval(as.symbol("a"))]
#[1] 1 1 3 4

Or the same with sym from rlang

a[eval(rlang::sym("a"))]
#[1] 1 1 3 4

Regarding why the changed code didn't work, order is applied on vector or columns, By using drop = FALSE, it is a data.frame

akrun
  • 874,273
  • 37
  • 540
  • 662
  • But the error message already appears at the subsetting step of the data frame. Besides, I added drop = TRUE to the argument, which in combination with `[` turns it into a vector, just like `[[` as only one column is selected in either case. And I still do not get why subsetting a list with a symbol works but subsetting a vector with a symbol does not. – FloHu Apr 02 '18 at 18:59
  • Sorry, just remembered that `drop = TRUE` is the default, I edited my post accordingly, the difference between `[` and `[[` still persists. – FloHu Apr 02 '18 at 21:06