MATLAB: Applying vectors of row and column indices without looping

I have a situation analogous to the following

z = magic(3)  % Data matrix

y = [1 2 2]' % Column indices

So,

z =      
       8 1 6               
       3 5 7      
       4 9 2

y represents the column index I want for each row. It's saying I should take row 1 column 1, row 2 column 2, and row 3 column 2. The correct output is therefore 8 5 9.

I worked out I can get the correct output with the following

x = 1:3;
for i = 1:3
    result(i) = z(x(i),y(i));
end

However, is it possible to do this without looping?

Upvotes: 0

Views: 46

Answers (2)

rayryeng
rayryeng

Reputation: 104474

Two other possible ways I can suggest is to use sub2ind to find the linear indices that you can use to sample the matrix directly:

z = magic(3);
y = [1 2 2];
ind = sub2ind(size(z), 1:size(z,1), y);
result = z(ind);

We get:

>> result

result =

     8     5     9

Another way is to use sparse to create a sparse matrix which you can turn into a logical matrix and then sample from the matrix with this logical matrix.

 s = sparse(1:size(z,1), y, 1, size(z,1), size(z,2)) == 1; % Turn into logical
 result = z(s);

We also get:

>> result

result =

     8
     5
     9

Be advised that this only works provided that each row index linearly increases from 1 up to the end of the rows. This conveniently allows you to read the elements in the right order taking advantage of the column-major readout that MATLAB is based on. Also note that the output is also a column vector as opposed to a row vector.

The link posted by Adriaan is a great read for the next steps in accessing elements in a vectorized way: Linear indexing, logical indexing, and all that.

Upvotes: 1

GameOfThrows
GameOfThrows

Reputation: 4510

there are many ways to do this, one interesting way is to directly work out the indexes you want:

 v = 0:size(y,2)-1; %generates a number from 0 to the size of your y vector -1
 ind = y+v*size(z,2); %generates the indices you are looking for in each row
 zinv = z';
 zinv(ind) 

 >> ans =

 8     5     9

Upvotes: 1

Related Questions