How to combine matrix of different size in a cell array into a matrix in MATLAB - matlab

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.

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));

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

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

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

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

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.

Related

How to enlarge matrix by repeating matrix rows? [duplicate]

This question already has answers here:
Matlab: repeat every column sequentially n times [duplicate]
(3 answers)
Closed 4 years ago.
Initial matrix is A = [ [1 2 3; 4 5 6; 7 8 9]. Every row is to be replicated 3 times such that the output matrix 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]
B = replicate(permute(A,[3 2 1]),3,1)
you mean like that?
kron(A,ones(3,1))
ans =
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
Since R2015a, there is a dedicated function for this: repelem.
A = [1 2 3; 4 5 6; 7 8 9]
B = repelem(A,3,1)
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
Or just indexing:
A = [1 2 3; 4 5 6; 7 8 9]; % original matrix
m = 3; % row repetition factor
n = 1; % column repetition factor
B = A(ceil(1/m:1/m:size(A,1)), ceil(1/n:1/n:size(A,2)));

Determining how many elements in a matrix are equal or bigger compared to another matrix element-wise

Let's say:
a = 1 2 3
4 5 6
7 8 9
b = 3 2 1
6 5 4
9 8 7
So in MATLAB: a = [1 2 3; 4 5 6; 7 8 9]; b = [3 2 1; 6 5 4; 9 8 7];. I want to know how many elements in a are equal or bigger than the element in the same place in b. So in this example, the result will be 6.
Let
a = [1 2 3
4 5 6
7 8 9];
b = [3 2 1
6 5 4
9 8 7];
then the expression
c = a>=b;
gives you the positions of the elements where a is larger than b.
sum(c(:));
Gives you the number of such elements.

Compare two matrices row by row and store indices of non-equal rows in Matlab

What is Matlab-way two compare two matrices row by row and store indices of non-equal rows (without for loops)?
I would do it in this way:
A = [1 2 3 4 5 6; 4 5 6 7 8 9; 1 3 5 7 9 1; 4 5 6 7 8 9; 1 3 5 7 9 1];
B = [0 2 3 4 5 6; 4 5 6 7 8 9; 1 5 5 7 9 1; 4 5 6 7 8 9; 1 3 5 7 9 1];
ind = find(sum(A - B, 2) ~= 0); %returns [1; 3]

How do I add mirrored padding around a matrix?

I have a matrix and want to add padding around it but the padded values have to be mirrored.
I have tried using A = padarray(B,[1 1],'symmetric','both');
but it mirrors the edge values of matrix B.
Meaning if
B = [1 2 3;
4 5 6;
7 8 9];
the result will be
A = [1 1 2 3 3;
1 1 2 3 3;
4 4 5 6 6;
7 7 8 9 9;
7 7 8 9 9]
But I need A to look like this:
A = [5 4 5 6 5;
2 1 2 3 2;
5 4 5 6 5;
8 7 8 9 8;
5 4 5 6 5]
Is there some function like padarray I can use for that or do I have to do it manually?
You could use symmetric with [2 2] and remove the extra parts,
B = [1 2 3; 4 5 6; 7 8 9];
c = padarray(B,[2 2],'both','symmetric');
c(end-1,:) = [];
c(:,end-1) = [];
c(:,2) = [];
c(2,:) = [];
gives,
c =
5 4 5 6 5
2 1 2 3 2
5 4 5 6 5
8 7 8 9 8
5 4 5 6 5

How do I make sums of sumatrixes in MATLAB without cycle?

I have a large matrix (time x frequency), which I want to reduce partially. I want to sum every 1000 rows (time-samples) together keepinq the frequency information, it is kind of a segmentation.
Is there any way to do it without any cycle in MATLAB?
A smaller example:
M=[1 2 3; 2 3 4; 5 8 7; 5 6 7; 1 2 3; 1 2 4];
and I want to sum every 2 rows together so, that I get:
[3 5 7; 10 14 14; 2 4 7]
Suppose you have a matrix with N rows and M columns and you want to sum every R rows together (where N is divisible by R),
>> mat = [1 2 3; 2 3 4; 5 8 7; 5 6 7; 1 2 3; 1 2 4]
mat =
1 2 3
2 3 4
5 8 7
5 6 7
1 2 3
1 2 4
>> [N, M] = size(mat); %=> [6, 3]
>> R = 2;
The following will allow you to sum groups of R rows:
>> res = reshape(mat, R, [])
res =
1 5 1 2 8 2 3 7 3
2 5 1 3 6 2 4 7 4
>> res = sum(res)
res =
3 10 2 5 14 4 7 14 7
>> res = reshape(res, [], M)
res =
3 5 7
10 14 14
2 4 7
You can also do everything in one line:
>> reshape(sum(reshape(mat, R, [])), [], M)
ans =
3 5 7
10 14 14
2 4 7