Sort one matrix based on another matrix

I am trying to put the rows of one matrix in the same order as the rows of another matrix of the same size. However, I cannot figure out how to do this without an explicit loop. It looks like I can do this using a subset and application or Map function, but I can't figure out how to do this.

Here is an example of a toy:

sortMe <- matrix(rnorm(6), ncol=2)
sortBy <- matrix(c(2,1,3, 1,3,2), ncol=2)

sorted <- sortMe 
for (i in 1:ncol(sortMe)) {
  sorted[,i] <- sortMe[,i][sortBy[,i]]
}

Using this method, the resulting matrix sortedcontains values ​​from sortMe, sorted in the same order as the matrix sortBy. Any idea how I would do this without a loop?

+5
source share
3 answers

This (using a two-column integer matrix to index the matrix of two dimensions) should do the trick:

sorted <- sortMe
sorted[] <- sortMe[cbind(as.vector(sortBy), as.vector(col(sortBy)))]
+8
source

lapply .

matrix(unlist(lapply(1:2, function(n) sortMe[,n][sortBy[,n]])), ncol=2)

, , ...

+3

I am going to invite you to exhibit my original version. I would say that the original loop you wrote is a little easier to read and understand (also probably easier to write) than the other suggested solutions.

Also, the loop is almost as fast as the other solutions: (I borrowed the @Josh O'Brien time code before he removed it from my post.)

set.seed(444)
n = 1e7
sortMe <- matrix(rnorm(2 * n), ncol=2)
sortBy <- matrix(c(sample(n), sample(n)), ncol=2)

#---------------------------------------------------------------------------
# @JD Long, original post.
system.time({
    sorted_JD <- sortMe
    for (i in 1:ncol(sortMe)) {
        sorted_JD[, i] <- sortMe[, i][sortBy[, i]]
    } 
})
#   user  system elapsed 
#  1.190   0.165   1.334 

#---------------------------------------------------------------------------
# @Julius (post is now deleted).
system.time({
    sorted_Jul2 <- sortMe
    sorted_Jul2[] <- sortMe[as.vector(sortBy) + 
        rep(0:(ncol(sortMe) - 1) * nrow(sortMe), each = nrow(sortMe))]
})
#   user  system elapsed 
#  1.023   0.218   1.226 

#---------------------------------------------------------------------------
# @Josh O'Brien
system.time({
    sorted_Jos <- sortMe
    sorted_Jos[] <- sortMe[cbind(as.vector(sortBy), as.vector(col(sortBy)))]
})
#   user  system elapsed 
#  1.070   0.217   1.274 

#---------------------------------------------------------------------------
# @Justin
system.time({
    sorted_Just = matrix(unlist(lapply(1:2,
        function(n) sortMe[,n][sortBy[,n]])), ncol=2)
})
#   user  system elapsed 
#  0.989   0.199   1.162 


all.equal(sorted_JD, sorted_Jul2)
# [1] TRUE
all.equal(sorted_JD, sorted_Jos)
# [1] TRUE
all.equal(sorted_JD, sorted_Just)
# [1] TRUE
+3
source

All Articles