51

I have a matrix with two columns of the following form:

1 349
1 393
1 392
4 459
3 49
3 32
2 94

I would like to sort this matrix in increasing order based on the first column but I would like to keep the corresponding values in the second column.

The output would look like this:

1 349
1 393
1 392
2 94
3 49
3 32
4 459
user1723765
  • 6,179
  • 18
  • 57
  • 85
  • 2
    Best answers so far that I've found: http://stackoverflow.com/questions/1296646/how-to-sort-a-dataframe-by-columns-in-r?rq=1 – Carl Witthoft Jun 27 '13 at 18:05

6 Answers6

51

Read the data:

foo <- read.table(text="1 349
  1 393
  1 392
  4 459
  3 49
  3 32
  2 94")

And sort:

foo[order(foo$V1),]

This relies on the fact that order keeps ties in their original order. See ?order.

Stephan Kolassa
  • 7,953
  • 2
  • 28
  • 48
12

Creating a data.table with key=V1 automatically does this for you. Using Stephan's data foo

> require(data.table)
> foo.dt <- data.table(foo, key="V1")
> foo.dt
   V1  V2
1:  1 349
2:  1 393
3:  1 392
4:  2  94
5:  3  49
6:  3  32
7:  4 459
Arun
  • 116,683
  • 26
  • 284
  • 387
  • 2
    Nice, +1! Is it documented that `data.table` keeps ties in the key in the original order? If not, could this potentially change in later versions of `data.table`? Changes like these can be extremely hard to find if they break scripts written with an older package version. – Stephan Kolassa Jan 16 '13 at 14:54
  • 5
    +1 too. @StephanKolassa, agreed. Yes this is documented and guaranteed. From `?data.table`: `The order of the rows within each group is preserved, as is the order of the groups.`. And in `?setkey` (in its own paragraph): `The sort is stable; i.e., the order of ties (if any) is preserved.`. – Matt Dowle Jan 18 '13 at 00:59
  • @Arun, OP had asked about sorting a `matrix`; is converting into a `data.table` and sorting better (=faster) than any other method that uses matrices directly? I was under the impression that dealing with matrices is faster than the list like `data.xxx` objects when possible. – Ameya Jul 27 '18 at 11:51
8

Be aware that if you want to have values in the reverse order, you can easily do so:

> example = matrix(c(1,1,1,4,3,3,2,349,393,392,459,49,32,94), ncol = 2)
> example[order(example[,1], decreasing = TRUE),]
     [,1] [,2]
[1,]    4  459
[2,]    3   49
[3,]    3   32
[4,]    2   94
[5,]    1  349
[6,]    1  393
[7,]    1  392
Gabriel123
  • 426
  • 5
  • 11
2

If your data is in a matrix named foo, the line you would run is

foo.sorted=foo[order(foo[,1]), ]

The order(foo[,1]) expression returns the elements from the first column of foo in ascending order. The foo[x, ] expression returns the rows of foo ordered according to the vector of indices x.

Hugo Manrique
  • 40
  • 3
  • 8
Ryan Olson
  • 21
  • 1
1

You do not need data.table.

This is what you need A[order(A[,1]), ], where A is the matrix of your data.

Vassilis Chasiotis
  • 427
  • 1
  • 3
  • 15
1

The accepted answer works like a charm unless you're applying it to a vector. Since a vector is non-recursive, you'll get an error like this

$ operator is invalid for atomic vectors

You can use [ in that case

foo[order(foo["V1"]),]
shubhamgoel27
  • 1,391
  • 10
  • 17