Juan Pablo
Juan Pablo

Reputation: 33

matlab matrix indexing of multiple columns

Say I have a IxJ matrix of values,

V= [1,4;2,5;3,6];

and a IxR matrix X of indexes,

X = [1 2 1 ; 1 2 2 ; 2 1 2];

I want to get a matrix Vx that is IxR such that for each row i, I want to read R times a (potentially) different column of V, which are given by the numbers in each corresponding column in X.

Vx(i,r) = V(i,X(i,r)).

For instance in this case it would be

Vx = [1,4,1;2,5,5;6,3,6];

Any help to do this fast, (without any looping) is much appreciated!

Upvotes: 2

Views: 522

Answers (3)

Divakar
Divakar

Reputation: 221574

You can use bsxfun for an efficient solution -

N = size(V,1)
Vx = V(bsxfun(@plus,[1:N]',(X-1)*N))

Sample run -

>> V
V =
     1     4
     2     5
     3     6
>> X
X =
     1     2     1
     1     2     2
     2     1     2
>> N = size(V,1);
Vx = V(bsxfun(@plus,[1:N]',(X-1)*N))
Vx =
     1     4     1
     2     5     5
     6     3     6

Upvotes: 4

user3667217
user3667217

Reputation: 2192

So what you want to achieve is using vectorization to achieve speed. This is one of the major strength of MATLAB. What you want is a matrix (index in the following code) whose elements are linear indexes that will be used to pick out value from the source matrix(V in your case). The first two lines of codes are doing exactly the same thing as sub2ind, turning subscripts to linear indexes. I'm coding this way so the logic of index conversion is clear.

[m,n] = ndgrid(1:size(X,1),1:size(X,2));
index = m + (X-1)*size(X,1);
Vx = V(index);

Upvotes: 4

rayryeng
rayryeng

Reputation: 104504

Another method would be to use repmat combined with sub2ind. sub2ind takes in row and column locations and the output are column-major linear indices that you can use to vectorize access into a matrix. Specifically, you want to build a 2D matrix of row indices and column indices which is the same size as X where the column indices are exactly specified as X but the row indices are the same for each row that we're concerned with. Concretely, the first row of this matrix will be all 1s, the next row all 2s, etc. To build this row matrix, first generate a column vector that goes from 1 up to as many rows as there are X and replicate this for as many columns as there are in X. With this new matrix and X, use sub2ind to generate column-major linear indices to finally index V to produce the matrix Vx:

subs = repmat((1:size(X,1)).', [1 size(X,2)]); %'
ind = sub2ind(size(X), subs, X);
Vx = V(ind);

Upvotes: 3

Related Questions