3

How do I turn a matrix:

[ 0.12 0.23 0.34 ;
  0.45 0.56 0.67 ;
  0.78 0.89 0.90 ] 

into a 'coordinate' matrix with a bunch of rows?

[ 1 1 0.12 ;
  1 2 0.23 ;
  1 3 0.34 ;
  2 1 0.45 ;
  2 2 0.56 ;
  2 3 0.67 ;
  3 1 0.78 ;
  3 2 0.89 ;
  3 3 0.90 ]

(permutation of the rows is irrelevant, it only matters that the data is in this structure)

Right now I'm using a for loop but that takes a long time.

Christian Chapman
  • 1,018
  • 10
  • 27

4 Answers4

9

Here is an option using ind2sub:

mat= [ 0.12 0.23 0.34 ;
  0.45 0.56 0.67 ;
  0.78 0.89 0.90 ] ;

[I,J] = ind2sub(size(mat), 1:numel(mat));
r=[I', J', mat(:)]

r =

    1.0000    1.0000    0.1200
    2.0000    1.0000    0.4500
    3.0000    1.0000    0.7800
    1.0000    2.0000    0.2300
    2.0000    2.0000    0.5600
    3.0000    2.0000    0.8900
    1.0000    3.0000    0.3400
    2.0000    3.0000    0.6700
    3.0000    3.0000    0.9000

Note that the indices are reversed compared to your example.

Cape Code
  • 3,584
  • 3
  • 24
  • 45
  • 1
    Alternatively, dropping one set of intermediates for neatness, `ind2sub(size(A), 1:numel(A))` – Notlikethat Feb 10 '14 at 22:47
  • He said a permutation of the rows is irrelevant, so this should be just as fine. The rows as such are still the same. (Referring to your note btw) – scenia Feb 11 '14 at 12:36
6
A = [ .12 .23 .34 ;
      .45 .56 .67 ;
      .78 .89 .90 ];

[ii jj] = meshgrid(1:size(A,1),1:size(A,2));
B = A.';
R = [ii(:) jj(:) B(:)];

If you don't mind a different order (according to your edit), you can do it more easily:

[ii jj] = ndgrid(1:size(A,1),1:size(A,2));
R = [ii(:) jj(:) A(:)];
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
5

In addition to generating the row/col indexes with meshgrid, you can use all three outputs of find as follows:

[II,JJ,AA]= find(A.'); %' note the transpose since you want to read across
M = [JJ II AA]
M =
            1            1         0.12
            1            2         0.23
            1            3         0.34
            2            1         0.45
            2            2         0.56
            2            3         0.67
            3            1         0.78
            3            2         0.89
            3            3          0.9

Limited application because zeros get lost. Nasty, but correct workaround (thanks user664303):

B = A.'; v = B == 0; %' transpose to read across, otherwise work directly with A
[II, JJ, AA] = find(B + v);
M = [JJ II AA-v(:)];

Needless to say, I would recommend one of the other solutions. :) In particular, ndgrid is the most natural solution to obtaining the row,col inds.

chappjc
  • 30,359
  • 6
  • 75
  • 132
1

I find ndgrid to be the most natural solution, but here's a fun way to do it manually with the odd couple of kron and repmat:

M = [kron(1:size(A,2),ones(1,size(A,1))).' ...  %' row indexes
     repmat((1:size(A,1))',size(A,2),1) ...     %' col indexes
     reshape(A.',[],1)]                         %' matrix values, read across

Simple adjustment to read down, as is natural in MATLAB:

M = [repmat((1:size(A,1))',size(A,2),1) ...     %' row indexes (still)
     kron(1:size(A,2),ones(1,size(A,1))).' ...  %' column indexes
     A(:)]                                      %  matrix values, read down

(Also since my first answer was obscenely hackish.)


I also find kron to be a nice tool to replicate each element at a time rather than than the entire array at a time, as repmat does. For example:

>> 1:size(A,2)
ans =
     1     2     3
>> kron(1:size(A,2),ones(1,size(A,1)))
ans =
     1     1     1     2     2     2     3     3     3

Taking this a bit further, we can generate a new function called repel to replicate elements of an array as opposed to the whole array:

>> repel = @(x,m,n) kron(x,ones(m,n));
>> repel(1:4,1,2)
ans =
     1     1     2     2     3     3     4     4
>> repel(1:3,2,2)
ans =
     1     1     2     2     3     3
     1     1     2     2     3     3
chappjc
  • 30,359
  • 6
  • 75
  • 132