1

I have a data.frame (a data.table in fact) that I need to sort by multiple columns. The names of columns to sort by are in a vector. How can I do it? E.g.

DF <- data.frame(A= 5:1, B= 11:15, C= c(3, 3, 2, 2, 1))
DF
  A  B C
  5 11 3
  4 12 3
  3 13 2
  2 14 2
  1 15 1

sortby <- c('C', 'A')

DF[order(sortby),] ## How to do this?

The desired output is the following but using the sortby vector as input.

DF[with(DF, order(C, A)),]
  A  B C
  1 15 1
  2 14 2
  3 13 2
  4 12 3
  5 11 3

(Solutions for data.table are preferable.)

EDIT: I'd rather avoid importing additional packages provided that base R or data.table don't require too much coding.

Jaap
  • 81,064
  • 34
  • 182
  • 193
dariober
  • 8,240
  • 3
  • 30
  • 47

3 Answers3

4

With :

setorderv(DF, sortby)

which gives:

> DF
   A  B C
1: 1 15 1
2: 2 14 2
3: 3 13 2
4: 4 12 3
5: 5 11 3

For completeness, with setorder:

setorder(DF, C, A)

The advantage of using setorder/setorderv is that the data is reordered by reference and thus very fast and memory efficient. Both functions work on data.table's as wel as on data.frame's.


If you want to combine ascending and descending ordering, you can use the order-parameter of setorderv:

setorderv(DF, sortby, order = c(1L, -1L))

which subsequently gives:

> DF
   A  B C
1: 1 15 1
2: 3 13 2
3: 2 14 2
4: 5 11 3
5: 4 12 3

With setorder you can achieve the same with:

setorder(DF, C, -A)
Jaap
  • 81,064
  • 34
  • 182
  • 193
2

Using dplyr, you can use arrange_at which accepts string column names :

library(dplyr)
DF %>% arrange_at(sortby)

#  A  B C
#1 1 15 1
#2 2 14 2
#3 3 13 2
#4 4 12 3
#5 5 11 3

Or with the new version

DF %>% arrange(across(sortby))

In base R, we can use

DF[do.call(order, DF[sortby]), ]
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
0

Also possible with dplyr:

DF %>%
    arrange(get(sort_by))

But Ronaks answer is more elegant.

Georgery
  • 7,643
  • 1
  • 19
  • 52