1

I have a matrix generated as follows:

set.seed(999)
mat.a = matrix(round(rnorm(24,4,9)),3,8)
mat.a

The mat.a looks like this:

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,]    1    6  -13   -6   12   -8   12   10
[2,]   -8    2   -7   16    6    5  -15    1
[3,]   11   -1   -5    5   13    5   -7    7

Now, suppose I would like to sort each row of mat.a from smallest to largest, but according to some group indices. As you see, there are 8 columns, corresponding to

grp.ids = as.factor(c(1,1,1,2,2,2,3,3))

i.e., the first 3 columns are for group 1, the next 3 columns are for group 2, and the last two columns are for group 3. What is desired is to sort within each group so that the result is a matrix (call it mat.b) like this:

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,]  -13    1    6   -8   -6   12   10   12
[2,]   -8   -7    2    5    6   16  -15    1
[3,]   -5   -1   11    5    5   13   -7    7

Is there a way to efficiently write a function by passing mat.a and grp.ids to obtain the sorted matrix mat.b? Applying some functions in plyr? Thanks a lot!

alittleboy
  • 10,616
  • 23
  • 67
  • 107

3 Answers3

3

You can write a function then apply it to each row:

sort.vec <- function(x, grp.ids) ave(x, grp.ids, FUN = sort)
t(apply(mat.a, 1, sort.vec, grp.ids))
flodel
  • 87,577
  • 21
  • 185
  • 223
2
 t( apply(mat.a, 1, function(row) row[order(c(1,1,1,2,2,2,3,3), row)] ) )
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,]  -13    1    6   -8   -6   12   10   12
[2,]   -8   -7    2    5    6   16  -15    1
[3,]   -5   -1   11    5    5   13   -7    7
IRTFM
  • 258,963
  • 21
  • 364
  • 487
1
matrix(unlist(lapply(split(mat.a, 1:nrow(mat.a)),
                     function(row) tapply(row, grp.ids, sort))),
       nrow = nrow(mat.a), byrow = TRUE)
eddi
  • 49,088
  • 6
  • 104
  • 155