3

While coding in GNU Octave/MATLAB I came through this simple problem I couldn't figure out by myself: I'm trying to select some elements of a matrix by using some indexes stored in an array. Let me put it clear with an example:

Given:

A = zeros(5, 3)

0   0   0
0   0   0
0   0   0
0   0   0
0   0   0

I would like to select some elements in A matrix row-wise, by using the values in the auxiliary array B as subindices.

Ie. the following B array

B = [ 1 3 2 1 3 ]'

1
3
2
1
3

should be read as:

1 -> index '1' on first row  (element [1, 1])
3 -> index '3' on second row (element [2, 3])
2 -> index '2' on third row  (element [3, 2])
1 -> index '1' on fourth row (element [4, 1])
3 -> index '3' on fifth row  (element [5, 3])

Therefore, if we assign value '1' to the elements selected using the aforementioned criteria, the resulting matrix would be:

1   0   0
0   0   1
0   1   0
1   0   0
0   0   1

I believe this is a simple operation and I'm convinced that there must be a way to achieve the described behaviour without having to loop across the rows in matrix A.

Thank you.

Edit: Rewrite question so that it is (hopefully) less confusing.

poinu
  • 73
  • 1
  • 8

1 Answers1

1

Your question is a bit confusing. You're saying you want to select the elements in A by using the values in the vector B as column indexes, but your example sets (not gets) new values in matrix A. I'm explaining both cases.

Consider this matrix

A = magic(5)

17   24    1    8   15
23    5    7   14   16
 4    6   13   20   22
10   12   19   21    3
11   18   25    2    9

Say you want to get/set the diagonal elements of A.

Index pairs in that case are [1,1], [2,2], [3,3], [4,4] and [5,5].

To access elements as a vector, run this

A(sub2ind([5,5], (1:5)',(1:5)'))

17
 5
13
21
 9

To set elements run this

A(sub2ind([5,5], (1:5)',(1:5)')) = 0

 0   24    1    8   15
23    0    7   14   16
 4    6    0   20   22
10   12   19    0    3
11   18   25    2    0

These commands can be written as

r = 1:5
c = 1:5
A(sub2ind([max(r),max(c)], r',c'))
# to assign values
A(sub2ind([max(r),max(c)], r',c')) = 0
# and to assign different value to each index pair
A(sub2ind([max(r),max(c)], r',c')) = [20 10 50 12 99]

In your example,

r = 1:5
c = B'
A(sub2ind([max(r),max(c)], r',c')) = 1
# or simply A(sub2ind([max(r),max(B)], r',B)) = 1

1   0   0
0   0   1
0   1   0
1   0   0
0   0   1

You can read how sub2ind works here.

narendra-choudhary
  • 4,582
  • 4
  • 38
  • 58
  • My question was a bit confusing indeed. I should have asked for 'getting/setting' the elements instead of 'selecting'. This solution was very explicative and solved my problem perfectly, thanks a lot. Finally I would like to say that the expression`A(sub2ind([max(r),max(c)], r',c'))` should perhaps be `A(sub2ind(size(A), r',c'))` instead or at least something like `A(sub2ind([size(A, 1) ,max(c)], r',c'))`. Otherwise, if `r` doesn't contain an index refering to the last row, the indices calculated by `sub2ind` won't be correct (because of how GNU Octave/MATLAB linear indexing is done). – poinu Dec 26 '15 at 19:46