Reputation: 1935
Let's create a fake test of three items only (n=3). One can answer each item either right (1) or wrong (0). There are only eight possibilities of the test results, i.e. all 1s, all 0s, and some combinations in between. The following code can be used to simulation this scenario:
n=3; m=0
while(m!=2^n) {
tmat = t(sapply(1:(10*2^n), function(x) sample(c(0,1), n, replace=T)))
pats = apply(tmat, 1, paste, collapse="/")
pats = unique(pats)
m = length(pats)
}
xmat = matrix(as.numeric(unlist(strsplit(pats, "/"))), ncol=n, nrow=m, byrow=T)
However, now I need to sort the rows of xmat and the results should look like this:
[,1] [,2] [,3] [,4]
[1,] 0 0 0 0
[2,] 1 0 0 1
[3,] 0 1 0 1
[4,] 0 0 1 1
[5,] 1 1 0 2
[6,] 1 0 1 2
[7,] 0 1 1 2
[8,] 1 1 1 3
I used this code to get the above results:
# create the fourth column which is the total score
xmat = cbind(xmat, rowSums(xmat))
# order by the 4th column, then 3rd column, then 2nd column.
xmat = xmat[order(xmat[,4], xmat[,3], xmat[,2]),]
My problem is that I will have any number of columns n in the future (n = 3 in this case). I cannot manually put n-1 terms in the code to order the matrix like this:
xmat = xmat[order(xmat[,n+1], xmat[,n], xmat[,n-1]), ... , xmat[,2])
Is there a easy way to do the last step?
Thank you in advance!
Upvotes: 0
Views: 102
Reputation: 89057
I think this should do it:
xmat[do.call(order, rev(split(xmat, col(xmat)))), ]
where:
split(xmat, col(xmat)
splits your matrix into a list of its columnsrev
reorders the list (last column first)do.call
calls order
on the listUpvotes: 4