2

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 Answers 6

5

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));
Sign up to request clarification or add additional context in comments.

Comments

2

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

Comments

0

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

Comments

0

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

Comments

0
[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}];

Comments

0

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.

1 Comment

(I'm guessing that finding the minimum dimension an N-dimensional cell array could be concatenated in general may be a non-trivial problem, which is why a brute-force approach might not be inappropriate here)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.