23

I have a matrix

df<-matrix(data=c(3,7,5,0,1,0,0,0,0,8,0,9), ncol=2)
rownames(df)<-c("a","b","c","d","e","f")

[,1] [,2]
a    3    0
b    7    0
c    5    0
d    0    8
e    1    0
f    0    9

and I would like to order the matrix in descending order first by column 1 and then by column two resulting in the matrix

df.ordered<-matrix(data=c(7,5,3,1,0,0,0,0,0,0,9,8),ncol=2)
rownames(df.ordered)<-c("b","c","a","e","f","d")

   [,1] [,2]
 b    7    0
 c    5    0
 a    3    0
 e    1    0
 f    0    9
 d    0    8

Any suggestions on how I could achieve this? Thanks.

Joshua
  • 40,822
  • 8
  • 72
  • 132
Elizabeth
  • 6,391
  • 17
  • 62
  • 90

3 Answers3

33

The order function should do it.

df[order(df[,1],df[,2],decreasing=TRUE),]
AJMansfield
  • 4,039
  • 3
  • 29
  • 50
Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
  • Would be nice to have a solution, where the number of columns I want to sort for can vary. – jmb Jan 29 '17 at 17:59
  • 2
    @jmb: you should ask your own question, with an example of how this solution isn't sufficient for your needs. I can think of a quick hack, but others can probably come up with something better than this: `df[do.call(order, c(decreasing = TRUE, data.frame(df[,1:2]))),]` – Joshua Ulrich Jan 29 '17 at 18:15
  • There is a function in [kdtools](https://github.com/thk686/kdtools) to sort a matrix or data frame in lexicographical order (or kd-tree order). You can select the columns using formula syntax. – THK Oct 07 '22 at 04:51
18

To complete the main answer, here is a way to do it programmatically, without having to specify the columns by hand:

set.seed(2013) # preparing my example
mat <- matrix(sample.int(10,size = 30, replace = T), ncol = 3)
mat
      [,1] [,2] [,3]
 [1,]    5    1    6
 [2,]   10    3    1
 [3,]    8    8    1
 [4,]    8    9    9
 [5,]    3    7    3
 [6,]    8    8    5
 [7,]   10   10    2
 [8,]    8   10    7
 [9,]   10    1    9
[10,]    9    4    5

As a simple example, let say I want to use all the columns in their order of appearance to sort the rows of the matrix: (One could easily give a vector of indexes to the matrix)

mat[do.call(order, as.data.frame(mat)),]   #could be ..as.data.frame(mat[,index_vec])..
      [,1] [,2] [,3]
 [1,]    3    7    3
 [2,]    5    1    6
 [3,]    8    8    1
 [4,]    8    8    5
 [5,]    8    9    9
 [6,]    8   10    7
 [7,]    9    4    5
 [8,]   10    1    9
 [9,]   10    3    1
[10,]   10   10    2
Antoine Lizée
  • 3,743
  • 1
  • 26
  • 36
5

order function will help you out, try this:

df[order(-df[,1],-df[,2]),] 
  [,1] [,2]
b    7    0
c    5    0
a    3    0
e    1    0
f    0    9
d    0    8

The minus before df indicates that the order is decreasing. You will get the same result setting decreasing=TRUE.

df[order(df[,1],df[,2],decreasing=TRUE),]
Jilber Urbina
  • 58,147
  • 10
  • 114
  • 138
Rub
  • 175
  • 1
  • 9