Suppose I have
arr = 2 1 3
1 2 3
1 1 2
How can I sort this into the below?
arr = 1 1 2
1 2 3
2 1 3
That is, first by column one, then by column two etc.
The function you're after is order
(how I arrived at this conclusion -- my first thought was "well, sorting, what about sort
?". Tried sort(arr)
which looks like it sorts arr
as a vector instead of row-wise. Looking at ?sort
, I see in the "See Also: order
for sorting on or reordering multiple variables.").
Looking at ?order
, I see that order(x,y,z, ...)
will order by x
, breaking ties by y
, breaking further ties by z
, and so on. Great - all I have to do is pass in each column of arr
to order
to do this. (There is even an example for this in the examples section of ?order
):
order( arr[,1], arr[,2], arr[,3] )
# gives 3 2 1: row 3 first, then row 2, then row 1.
# Hence:
arr[ order( arr[,1], arr[,2], arr[,3] ), ]
# [,1] [,2] [,3]
#[1,] 1 1 2
#[2,] 1 2 3
#[3,] 2 1 3
Great!
But it is a bit annoying that I have to write out arr[,i]
for each column in arr
- what if I don't know how many columns it has in advance?
Well, the examples show how you can do this too: using do.call
. Basically, you do:
do.call( order, args )
where args
is a list of arguments into order
. So if you can make a list out of each column of arr
then you can use this as args
.
One way to do this is is to convert arr
into a data frame and then into a list -- this will automagically put one column per element of the list:
arr[ do.call( order, as.list(as.data.frame(arr)) ), ]
The as.list(as.data.frame
is a bit kludgy - there are certainly other ways to create a list such that list[[i]]
is the i
th column of arr
, but this is just one.
This would work:
arr[do.call(order, lapply(1:NCOL(arr), function(i) arr[, i])), ]
What it is doing is:
arr[order(arr[, 1], arr[, 2], arr[ , 3]), ]
except it allows an arbitrary number of columns in the matrix.
I wrote this little func that does decreasing order as well cols allows to choose which columns to order and their order
ord.mat = function(M, decr = F, cols = NULL){
if(is.null(cols))
cols = 1: ncol(M)
out = do.call( "order", as.data.frame(M[,cols]))
if (decr)
out = rev(out)
return(M[out,])
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With