2
votes

Similarly to How to combine vectors of different length in a cell array into matrix in MATLAB I would like to combine matrix having different dimension, stored in a cell array, into a matrix having zeros instead of the empty spaces. Specifically, I have a cell array {1,3} having 3 matrix of size (3,3) (4,3) (4,3):

A={[1 2 3; 4 5 6; 7 8 9]  [1 2 3; 4 5 6; 7 8 9; 9 9 9]  [1 2 3; 4 5 6; 7 8 9; 4 4 4]}

and I would like to obtain something like:

B =

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

I tried using cellfun and cell2mat but I do not figure out how to do this. Thanks.

6

6 Answers

0
votes

I would be surprised if this is possible in one or a few lines. You will probably have to do some looping yourself. The following achieves what you want in the specific case of incompatible first dimension lengths:

A={[1 2 3; 4 5 6; 7 8 9]  [1 2 3; 4 5 6; 7 8 9; 9 9 9]  [1 2 3; 4 5 6; 7 8 9; 4 4 4]}

maxsize = max(cellfun(@(x) size(x, 1), A));
B = A;
for k = 1:numel(B)
    if size(B{k}, 1) < maxsize
        tmp = B{k};
        B{k} = zeros(maxsize, size(tmp,1));
        B{k}(1:size(tmp,1),1:size(tmp,2)) = tmp;
    end
end

B = cat(2, B{:});

Now B is:

B =

     1     2     3     1     2     3     1     2     3
     4     5     6     4     5     6     4     5     6
     7     8     9     7     8     9     7     8     9
     0     0     0     9     9     9     4     4     4
5
votes

Even if other answers are good, I'd like to submit mine, using cellfun.

l = max(cellfun(@(x) length(x),A))

B = cell2mat(cellfun(@(x) [x;zeros(l-length(x),3)], A, 'UniformOutput', 0));
2
votes

Using bsxfun's masking capability -

%// Convert A to 1D array
A1d = cellfun(@(x) x(:).',A,'Uni',0) %//'

%// Get dimensions of A cells
nrows = cellfun('size', A, 1)
ncols = cellfun('size', A, 2)

%// Create a mask of valid positions in output numeric array, where each of
%// those numeric values from A would be put
max_nrows = max(nrows)
mask = bsxfun(@le,[1:max_nrows]',repelem(nrows,ncols))  %//'

%// Setup output array and put A values into its masked positions
B = zeros(max_nrows,sum(ncols))
B(mask) = [A1d{:}]

Sample run

Input -

A={[1 2 3 5 6; 7 8 9 3 8]  [1 2 3; 4 5 6; 7 8 9; 9 9 9]  [1 2 3; 4 5 6; 7 8 9; 4 4 4]}

Output -

B =
     1     2     3     5     6     1     2     3     1     2     3
     7     8     9     3     8     4     5     6     4     5     6
     0     0     0     0     0     7     8     9     7     8     9
     0     0     0     0     0     9     9     9     4     4     4
0
votes

I would do it using a good-old for loop, which is quite intuitive I think.

Here is the commented code:

clc;clear var


A={[1 2 3; 4 5 6; 7 8 9]  [1 2 3; 4 5 6; 7 8 9; 9 9 9]  [1 2 3; 4 5 6; 7 8 9; 4 4 4]};

%// Find the maximum rows and column # to initialize the output array.
MaxRow = max(cell2mat(cellfun(@(x) size(x,1),A,'Uni',0)));
SumCol = sum(cell2mat(cellfun(@(x) size(x,2),A,'Uni',0)));

B = zeros(MaxRow,SumCol);

%// Create a counter to keep track of the current columns to fill
ColumnCounter = 1;
for k = 1:numel(A)    
    %// Get the # of rows and columns for each cell from A
    NumRows = size(A{k},1);
    NumCols = size(A{k},2);

    %// Fill the array
    B(1:NumRows,ColumnCounter:ColumnCounter+NumCols-1) = A{k};

    %// Update the counter
    ColumnCounter = ColumnCounter+NumCols;
end
disp(B)

Output:

B =

     1     2     3     1     2     3     1     2     3
     4     5     6     4     5     6     4     5     6
     7     8     9     7     8     9     7     8     9
     0     0     0     9     9     9     4     4     4
0
votes
[max_row , max_col] = max( size(A{1}) , size(A{2}) , size(A{3}) );
A{1}(end:max_row , end:max_col)=0;
A{2}(end:max_row , end:max_col)=0;
A{3}(end:max_row , end:max_col)=0;
B=[A{1} A{2} A{3}];
0
votes

for this specific problem, simply this will do:

B=cat(1,A{:}); 

or what I often just give a try for 2D cells, and works for your example as well:

B=cell2mat(A'); 

if you literally don't give a f* what dimension it will be cut in (and you're exceedingly lazy): put the same into a try-catch-block and loop over some dims as below.

function A=cat_any(A)
for dims=1:10% who needs more than 10 dims? ... otherwise replace 10 with: max(cellfun(@ndims,in),[],'all')
  try, A=cat(dims,A{:}); end
  if ~iscell(A), return A; end
end
disp('Couldn''t cat!') %if we can't cat, tell the user
end

Beware, this might lead to unexpected results ... but in most cases simply just worked for me.