17

How can I use dplyr::arrange(dplyr::desc()) and pass in a string as the column name?

Here is a sample dataset:

df <- data.frame(a = 1:3, b = 3:1)

Examples that work:

df %>% dplyr::arrange(b)
df %>% dplyr::arrange_("b")
df %>% dplyr::arrange(dplyr::desc(b))

But I can't seem to use a string with both arrange and desc, these are the two version I tried that don't work:

df %>% dplyr::arrange(dplyr::desc("b"))
df %>% dplyr::arrange_(dplyr::desc("b"))

Thanks!

jbaums
  • 27,115
  • 5
  • 79
  • 119
DeanAttali
  • 25,268
  • 10
  • 92
  • 118
  • 1
    May be like this `df %>% dplyr::arrange(dplyr::desc(df["b"]))`? Frankly, I'm unsure... – KFB Nov 20 '14 at 08:31
  • You'll need to use interp – hadley Nov 20 '14 at 17:32
  • Thanks for the tips and dupe findings, but I still can't figure out how to use interp (from the lazyeval package?) to make this simple example work. I'll keep trying to understand NSE but it would be amazing if you could also post the solution if it doesn't take you too much time. Thanks a lot anyway – DeanAttali Nov 20 '14 at 21:01
  • 1
    Quote from Henrik's comment on my deleted answer: " `df <- data.frame(a = 3:1, b = 1:3)`; Variable to sort by as a string: `sort_var <- "b"`; Then using the example in the vignette which I referred to: `df %>% arrange_(interp(~desc(var), var = as.name(sort_var)))` " Also make sure you first install and load the package `lazyeval`. – talat Nov 22 '14 at 09:50
  • A new convenience function `desc_ <- function(x) { lazyeval::interp(~desc(var), var = as.name(x)) }` is nice – saladi Apr 13 '17 at 17:45

1 Answers1

15

tl;dr : df %>% arrange(desc(!!sym("b")))

First of all the standard evaluations of dplyr verbs are deprecated, so instead of:

library(dplyr)
x <- "b"
df %>% arrange_(x)

it is now recommended to type:

library(dplyr)
library(rlang)
df %>% arrange(!!sym(x))

See ?arrange_ , it links to a help topic named Deprecated SE versions of main verbs. and offers some details.

From there to sort descending it is straightforward to adapt the new formulation :

df %>% arrange(desc(!!sym(x)))

These work as well if your data is not grouped:

df %>% arrange(desc(.[[x]]))
df %>% arrange(desc(.data[[x]]))

FYI, to make it work with arrange_ we could have done the following, better use the approach above however!

df %>% arrange_(paste0("desc(",x,")"))

Which can be simplified if we have numeric variables like in OP's example:

df %>% arrange_(paste0("-",x))

Or using lazyeval::interp

df %>% arrange_(interp(~desc(y),y=as.name(x)))

Or as @shyam-saladi proposes:

desc_ <- function(x) lazyeval::interp(~desc(var), var = as.name(x))
# or just
# desc_ <- function(x) paste0("desc(",x,")")
df %>% arrange_(desc_(x))
moodymudskipper
  • 46,417
  • 11
  • 121
  • 167