How to sort a matrix by all columns

后端 未结 4 1403
灰色年华
灰色年华 2020-12-15 10:04

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
         


        
相关标签:
4条回答
  • 2020-12-15 10:28

    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,])
    }
    
    0 讨论(0)
  • 2020-12-15 10:36

    I had a similar problem, and solution seems to be simple and elegant:

    t(apply(t(yourMatrix),2,sort))
    
    0 讨论(0)
  • 2020-12-15 10:40

    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.

    0 讨论(0)
  • 2020-12-15 10:43

    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 ith column of arr, but this is just one.

    0 讨论(0)
提交回复
热议问题