Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MATLAB Sort 2D and 3D matrix and access through index

Let's said you have a 1D matrix

a = rand(1,5);
[sa i] = sort(a);

then sa and a(i) are the same. However, if the size of the matrix increases

a = rand(3,4);
[sa i] = sort(a);

then sa and a(i) are not the same. And the same happens when I'm trying to sort a 3D matrix by its third dimension.

How can I access the values of a through the index i? Or in other words how can I compute the sa=a(X), what X should be?

Edit:

Thanks for the solutions. However, they don't work when you change the dimension to sort by. Nevertheless, I pick up the idea and use it to build a general form.

What the algorithm is doing is to build the indexes of the matrix. MATLAB index the cells column wise. Therefore, the index is given by

idx = r + (c-1)*ROWS + (p-1)*ROWS*COLS

where, idx is the index, r is the row position, c is the column position, and p is the page position.

Therefore, if we sort in the first dimension (normal sort(a)) the result index is the position in the columns; if we sort in the second dimension, the result index is the position in the rows; and if we sort in the third dimension, the result index is the page position. This being said, it only last to produce the rows and cols for the given case:

r = repmat((1:rows)',[1 cols pages]);
c = repmat(1:cols,[rows 1 pages]);

Sorting in the first dimension is explained in the solutions given. Then, lets sort in the second dimension (row wise) of a two dimensional array

a = rand(4,5);
[rows cols pages] = size(a);
R = repmat((1:rows)',[1 cols pages]);
[sa idx] = sort(a,2);
nIdx = R + (idx-1)*rows;
isequal(sa,a(nIdx))

Now, if we use the same idea for sorting in the third dimension (page wise), we need to do

a = rand(4,5,3);
[rows cols pages] = size(a);
R = repmat((1:rows)',[1 cols pages]);
C = repmat(1:cols,[rows 1 pages]);
[sa idx] = sort(a,3);
nIdx = R + (C-1)*rows + (idx-1)*rows*cols;
isequal(sa,a(nIdx))

And the same logic can be used to extend it to N dimensions. Thanks for your help, you en light the way. :)

like image 237
adn Avatar asked Apr 13 '11 01:04

adn


People also ask

How do you sort a matrix value 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 I use Sortrows in Matlab?

B = sortrows( A ) sorts the rows of a matrix in ascending order based on the elements in the first column. When the first column contains repeated elements, sortrows sorts according to the values in the next column and repeats this behavior for succeeding equal values.

How do you find the index of a value in Matlab?

In MATLAB the array indexing starts from 1. To find the index of the element in the array, you can use the find() function. Using the find() function you can find the indices and the element from the array. The find() function returns a vector containing the data.


2 Answers

[sa, i]=sort(a) returns the ordered indices for each column. You just need to get the correct linear indices for the matrix. So, for a 2D matrix,

A=rand(3,4);
[rows,cols]=size(A);
[B,index]=sort(A,1);
correctedIndex=index+repmat(0:cols-1,rows,1)*rows;

Now test it:

A =

    0.9572    0.1419    0.7922    0.0357
    0.4854    0.4218    0.9595    0.8491
    0.8003    0.9157    0.6557    0.9340

B =

    0.4854    0.1419    0.6557    0.0357
    0.8003    0.4218    0.7922    0.8491
    0.9572    0.9157    0.9595    0.9340

A(correctedIndex)

ans =

    0.4854    0.1419    0.6557    0.0357
    0.8003    0.4218    0.7922    0.8491
    0.9572    0.9157    0.9595    0.9340
like image 51
abcd Avatar answered Oct 05 '22 11:10

abcd


You can create a general vectorized solution that will work for any N-D matrix or sort dimension by using the functions IND2SUB and SUB2IND. Here, I've packaged this solution up into a new function sort_linear_index, which will behave just like the function SORT except that it will return linear indices so that B = A(IX) will always work no matter what size A is.

function [sortedA,sortIndex] = sort_linear_index(A,sortDim,sortOrder)
%#SORT_LINEAR_INDEX   Just like SORT, but returns linear indices

  sizeA = size(A);  %# Get the matrix size
  if nargin < 2
    sortDim = find(sizeA > 1,1);  %# Define sortDim, if necessary
  end
  if nargin < 3
    sortOrder = 'ascend';  %# Define sortOrder, if necessary
  end
  [sortedA,sortIndex] = sort(A,sortDim,sortOrder);  %# Sort the matrix
  [subIndex{1:numel(sizeA)}] = ...  %# Create a set of matrix subscripts
     ind2sub(sizeA,reshape(1:prod(sizeA),sizeA));
  subIndex{sortDim} = sortIndex;  %# Overwrite part of the subscripts with
                                  %#   the sort indices
  sortIndex = sub2ind(sizeA,subIndex{:});  %# Find the linear indices

end

And now we can test the function out:

>> A = rand(1,10);
>> [B,IX] = sort_linear_index(A);  %# Sort a row vector
>> isequal(B,A(IX))
ans =
     1
>> A = rand(3,4,3);
>> [B,IX] = sort_linear_index(A,1);  %# Sort a 3-by-4-by-3 matrix along
>> isequal(B,A(IX))                  %#   the first dimension
ans =
     1
>> [B,IX] = sort_linear_index(A,3);  %# Sort a 3-by-4-by-3 matrix along
>> isequal(B,A(IX))                  %#   the third dimension
ans =
     1
>> [B,IX] = sort_linear_index(A,2,'descend');  %# Sort a 3-by-4-by-3 matrix along
>> isequal(B,A(IX))                            %#   the second dimension
ans =                                          %#   in descending order
     1
like image 34
gnovice Avatar answered Oct 05 '22 11:10

gnovice