Search code examples
matlabloopsmatrixcell

Matlab: Appending matrices from a cell diagonally into a new matrix of zeros


I have a problem I am trying to solve that creates an Nx1 cell where the data stored inside it are always N number of 2x2 matrices.

Example:

N = 2
mycell = cell(N,1); 
for i =1:N;
    mycell{i} = randi([0, 10], 2);
end 

newmatrix = zeros (N+1); 

So say mycell{1} looks like:

[3 5
 2 1]

and mycell{2} looks like:

[6 9;
 3 2]

My new matrix of zeros looks like:

[0 0 0
 0 0 0
 0 0 0]

I want to get it too look like this (joining the last element of the first cell with the first element of the next cell in this sort of diagonal setup):

[3 5 0
 2 7 9
 0 3 2]

Is there a simple way to do this or any built in Matlab functions that may help?

Thank you.


Solution

  • Here's a solution based on accumarray. It doesn't use loops, and it works for generic sizes N (number of matrices), R (number of rows of each matrix) and C (number of columns of each matrix):

    Generate example data (using a generalization of the code in the question):

    N = 3; % number of matrices
    R = 2; % number of rows of each matrix
    C = 3; % number of columns of each matrix
    mycell = cell(N,1); 
    for i =1:N;
        mycell{i} = randi([0, 10], [R C]);
    end
    

    The following steps are used:

    1. Build row and column indices with the appropriate staggering;
    2. Concatenate the cell array and linearize, so that all data is in a column vector;
    3. Apply accumarray to build the result matrix, summing values with the same indices.

    Code:

    indCol = repmat((0:N-1)*(R-1)+(1:R).', C, 1);
    indRow = repelem((0:N-1)*(C-1)+(1:C).', R, 1);
    newmatrix = accumarray([indCol(:) indRow(:)], reshape(cat(3, mycell{:}), 1, []));
    

    Example result:

    >> celldisp(mycell)
    mycell{1} =
         3     1     2
         5     6     7
    mycell{2} =
         7     4     2
         8     0    10
    mycell{3} =
         1     5     0
         9    10     4
    >> newmatrix
    newmatrix =
         3     1     2     0     0     0     0
         5     6    14     4     2     0     0
         0     0     8     0    11     5     0
         0     0     0     0     9    10     4