4

Say

X = [1 2;
     3 4];
c = [1 2]';

I would like to find some way of doing what it seems to me like X(:,c) should do. To write it as a for loop:

for i=1:n
   res(i) = X(i, c(i));
end
% res = [1 4]

is there a single statement / vectorized way of doing this?

Xodarap
  • 11,581
  • 11
  • 56
  • 94
  • similar question: [MATLAB indexing question](http://stackoverflow.com/q/4842512/97160) – Amro May 27 '12 at 01:02

2 Answers2

9

diag(X(:,c)) should do the trick

Explanation: A (slightly more complicated) example will help understand.

>>X = [1 2; 3 4; 5 6; 7 8]

X =

     1     2
     3     4
     5     6
     7     8

>> c = [1 1 2 1];
>> R = X(:,c)

R =

     1     1     2     1
     3     3     4     3
     5     5     6     5
     7     7     8     7

So what's going on here? For each element in vector c, you're picking one of the columns from the original matrix X: For the first column of R, use the first column of X. For the second column of R, use the first column of X (again). For the third column of R, use the second column of X... and so on.

The effect of this is that the element you're interested in (defined in c) is located along the diagonal of the matrix R. Get just the diagonal using diag:

>>diag(R)

ans =

1
3
6
7
tmpearce
  • 12,523
  • 4
  • 42
  • 60
  • This only works for the example Xodarap provided, if `c` isn't coincidentally equal to `1:length(X)`, this will not do what he requested, ie retrieve `X(i, c(i))` – Gunther Struyf May 26 '12 at 23:57
  • @GuntherStruyf Sure it will: `X=[1 2 3;4 5 6]; c=[3 1]; diag(X(:,c)) -> [6 1]`. Note that I didn't do `diag(X)` but rather `diag` on a matrix formed from the columns of `X` specified in `c` – tmpearce May 27 '12 at 00:21
  • You're right that this works, but could you explain why? I don't really understand what `X(:,c)` is returning me. – Xodarap May 27 '12 at 02:20
  • @Xodarap Explanation added... let me know if you need more, or if that makes sense. – tmpearce May 27 '12 at 02:42
4

Use sub2ind to convert to linear indices

X = [1 2;
     3 4];
c = [1 2]';

idx = sub2ind(size(X),1:numel(c),c(:)');
res = X(idx);

(I used c(:)' to get c in the correct size.)

Result:

res =

 1     4
Gunther Struyf
  • 11,158
  • 2
  • 34
  • 58