Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort a matrix based on the order given in a second matrix (MATLAB)

Tags:

sorting

matlab

I have a bigmatrix that is sorted. However, I need to re-order it as per the order of IDs in another matrix (col. 1 here for both matrices). How can I do this using vectorization? Eg:

bigmat = [ ...
            1 10 ; 
            1 30 ; 
            1 40 ; 
            2 1  ; 
            2 11 ; 
            3 58 ; 
            4 2  ;
            4 5 ] ;

ordermat = [ 2 ; 1 ; 4 ; 3 ; 6] ;       % Integer IDs

finalans = [ ...
            2 1  ; 
            2 11 ; 
            1 10 ; 
            1 30 ; 
            1 40 ;
            4 2  ;
            4 5  ;
            3 58 ; ] ;

It is possible that all some IDs (integers here) in ordermat may not be present in bigmat. They can be ignored as shown above with id = 6. Thanks!

like image 984
Maddy Avatar asked Aug 11 '11 21:08

Maddy


People also ask

How do you sort a matrix in MATLAB?

B = sort( A ) sorts the elements of A in ascending order. If A is a vector, then sort(A) sorts the vector elements. If A is a matrix, then sort(A) treats the columns of A as vectors and sorts each column.

How do you sort a matrix based on one column in MATLAB?

B = sortrows( A , column ) sorts A based on the columns specified in the vector column . For example, sortrows(A,4) sorts the rows of A in ascending order based on the elements in the fourth column.

How do you sort a matrix by a column in descending order in MATLAB?

The SORTROWS function offers the ability to sort the rows of a matrix in descending order by specifying a negative value for the appropriate column in the second argument to the function.


2 Answers

Here is my solution:

ordermat = [2; 1; 4; 3; 6];
bigmat = [
    1 10
    1 30
    1 40
    2 1
    2 11
    3 58
    4 2
    4 5
];
%#bigmat = sortrows(bigmat,1);

%# keep valid IDs, 
ord = ordermat( ismember(ordermat,bigmat(:,1)) );
ord = grp2idx(ord);

%# starting/ending locations of the different IDs in bigmat
startInd = find( diff([0;bigmat(:,1)]) );
endInd = [startInd(2:end)-1; size(bigmat,1)];

%# generate startInd(i):endInd(i) intervals
ind = arrayfun(@colon, startInd, endInd, 'UniformOutput',false);

%# order then combine the intervals of indices
ind = [ind{ord}];

%# get final sorted result
finalans = bigmat(ind,:);

I made sure it handles different cases like:

  • ordermat contains IDs not found in bigmat: ordermat = [2;1;4;3;6]
  • not all IDs of bigmat are represented in ordermat: ordermat = [2;1]
  • IDs not sequential and/or not starting at 1: ordermat=ordermat+10; bigmat=bigmat+10;
like image 149
Amro Avatar answered Oct 14 '22 18:10

Amro


%# Input values:
bigmat = [1 10; 1 30; 1 40; 2 1; 2 11; 3 58;  4 2; 4 5];
ordermat = [ 2 ; 1 ; 4 ; 3 ; 6] ;   

%# Make a look-up table that tells us the relative order for each order id
sortmat(ordermat) = 1:length(ordermat);

%# Extract the order ID's from the big matrix
keys = bigmat(:,1);

%# Get the new ordering
new_key = sortmat(keys);

%# Sort the new ordering, remembering the permutation necessary
[~, permutation] = sort(new_key);

%# Apply the permutation to the big matrix
finalans = bigmat(permutation, :);
like image 34
nibot Avatar answered Oct 14 '22 18:10

nibot