Stacking matrices from a cell array on top of one another (MATLAB) - matlab

I have a cell array, with each cell containing a 3 column matrix.
How can I stack all of these matrices together, so that there are 3 very long columns of data?
I know I could do:
stacked_matrix = [cellArray{1,1} ; cellArray{1,2} ; cellArray{1,N}];
but I want to avoid manually writing everything out because the cell array is 1x40

You can achieve this using cat along the first dimension like this:
cat(1,cellArray{:})
Let's test it:
>> cellArray{1} = [ 1 2 3];
>> cellArray{2} = [ 4 5 6];
>> cellArray{3} = [ 7 8 9];
>> cellArray{4} = [10 11 12];
>> stacked_matrix = cat(1,cellArray{:})
stacked_matrix =
1 2 3
4 5 6
7 8 9
10 11 12

You can also use vertcat as well:
out = vertcat(cellArray{:});
However, doing vertcat is essentially syntactic sugar for cat(1,cellArray{:}) as per Matt's answer.
To test:
cellArray{1} = [ 1 2 3];
cellArray{2} = [ 4 5 6];
cellArray{3} = [ 7 8 9];
cellArray{4} = [10 11 12];
out = vertcat(cellArray{:});
... and we get:
out =
1 2 3
4 5 6
7 8 9
10 11 12

Related

MATLAB: fprintf/sprintf to print string + matrix

I wanted to know, if it's possible to print a string followed by a matrix, written in the classic form, for example:
5 5 9
>>your matrix is M = 1 4 2
2 1 3
using fprintf/sprintf.
If your matrix doesn't have to be on the same line as the text, you can do something as simple as replacing ; with \n in the output of mat2str:
A=[1 2 3; 4 5 6; 7 8 9];
intro_str = 'Your matrix is:\n';
sprintf([intro_str strrep(mat2str(A),';','\n ')])
Your matrix is:
[1 2 3
4 5 6
7 8 9]
If, however, you want to have them on the same line, the only way I see how this can be done is by computing the amount of tabs (\t) or spaces you need on every "non-intro" line, approximately like this:
A=[1 2 3; 4 5 6; 7 8 9];
intro_str = 'Your matrix is: ';
%// ntabs = ceil(length(intro_str)/3);
%// tab_blanks = cellstr(repmat('\t',size(A,2),ntabs));
spaces = blanks(length(intro_str));
space_blanks = repmat(spaces,size(A,2),1);
mid_row = ceil(size(A,1)/2);
%// tab_blanks(mid_row) = {intro_str};
space_blanks(mid_row,:) = intro_str;
final_str = [space_blanks repmat('%u\t',size(A,1),size(A,2)) repmat('\n',size(A,1),1)]';
final_str = horzcat(final_str(:))';
sprintf(final_str,A(:))
ans =
1 4 7
Your matrix is: 2 5 8
3 6 9

How to combine matrix of different size in a cell array into a matrix in 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.

vec2mat w/ different number of columns

Referring to Reshape row wise w/ different starting/ending elements number #Divakar came with a nice solution but, what if the number of columns is not always the same?
Sample run -
>> A'
ans =
4 9 8 9 6 1 8 9 7 7 7 4 6 2 7 1
>> out
out =
4 9 8 9 0 0
6 1 8 9 7 7
7 4 6 2 7 1
I took only the first 4 terms of A and put them in out, then fill the rest 2 empty cell with 0's. So the ncols = [4 6 6]. Unfortunately vet2mat doesn't allow vector as columns number.
Any suggestions?
You can employ bsxfun's masking capability here -
%// Random inputs
A = randi(9,1,15)
ncols = [4 6 5]
%// Initialize output arary of transposed size as compared to the desired
%// output arary size, as we need to insert values into it row-wise and MATLAB
%// follows column-major indexing
out = zeros(max(ncols),numel(ncols));
mask = bsxfun(#le,[1:max(ncols)]',ncols); %//'# valid positions mask for output
out(mask) = A; %// insert input array elements
out = out.' %//'# transpose output back to the desired output array size
Code run -
A =
5 3 7 2 7 2 4 6 8 1 9 7 5 4 5
ncols =
4 6 5
out =
5 3 7 2 0 0
7 2 4 6 8 1
9 7 5 4 5 0
You could use accumarray for that:
A = [4 9 8 9 6 1 8 9 7 7 7 4 6 2 7 1].'; %'// data
ncols = [4 6 6]; %// columns
n = max(ncols);
cs = cumsum(ncols);
ind = 1;
ind(cs+1) = 1;
ind = cumsum(ind(1:end-1)); %// `ind` tells the row for each element of A
result = accumarray(ind(:), A(:), [], #(x) {[x; zeros(n-numel(x),1)]}); %// split `A` as
%// dictated by `ind`, and fill with zeros. Each group is put into a cell.
result = [result{:}].'; %'// concatenate all cells

comparison and shifting strings/arrays with different length in matlab

I have a list of strings or arrays with different length or size. I want to use the shortest string and compare with other strings by shifting the shortest string window one by one to do comparison.
Let's say I want to do addition, I have [2 1 3] as my shortest list and want to perform addition on [4 5 7 8 9]
1st addition: [2 1 3] + [4 5 7]
2nd addition: [2 1 3] + [5 7 8]
3rd addition: [2 1 3] + [7 8 9]
How can i do this using matlab?
Thanks
Say A is the longer vector and B the shorter one.
You can use hankel function to create a matrix where each row is a window of length 3 over A
>> hankel(A(1:3),A(3:end))
ans =
4 5 7
5 7 8
7 8 9
Now you just need to call bsxfun to do the desired action on each row:
L=numel(B);
bsxfun(#plus, B, hankel(A(1:L),A(L:end)))
results in
ans =
6 6 10
7 8 11
9 9 12
Where rows contain the desired output vectors.
Note that you can change #plus to #minus or any other user-defined function.
A simpler approach, if you don't care much about speed is using arrayfun and cell2mat. Note that this approach doesn't check which vector is which. a must be shorter than b.
a =
1 2 3
b =
1 3 5 2 4 6
c = cell2mat(arrayfun(#(n) a+b(n:n+numel(a)-1), 1:numel(b)-numel(a)+1,'UniformOutput',0).')
c =
2 5 8
4 7 5
6 4 7
3 6 9
You can create indices of a sliding window using hankel. Example:
a = [2 1 3];
b = [4 5 7 8 9];
idx = hankel(1:numel(a), numel(a):numel(b));
c = bsxfun(#plus, b(idx.'), a);
The result:
>> c
c =
6 6 10 % [2 1 3] + [4 5 7]
7 8 11 % [2 1 3] + [5 7 8]
9 9 12 % [2 1 3] + [7 8 9]
(Note: This assumes b is longer than a, swap them if otherwise).
I think you should do the following, assuming row arrays of doubles:
lenList(1) = length(list1);
lenList(2) = length(list2);
% find minumum length
[minLen, idx] = min(lenList);
% find length difference
lenDiff = abs(diff(lenList));
% initialize result
result = zeros(lenDiff + 1, minLen);
% Check which list is the longest
if idx == 1
shortList = list1;
longList = list2;
else
shortList = list2;
longList = list1;
end
% Perform math
for ii = 1:(lenDiff + 1)
result(ii, :) = shortList + longList(ii:(ii+minLen-1))
end

How do I Combine two equal sized vectors element wise in MatLab?

I have two vectors:
a = [1 3 5 7 9];
b = [2 4 6 8 10];
That I need to combine together element wise. Meaning that I need the first element of vector a, then the first element of vector b, second of a, second of b, and so forth until I get the following:
combined = [1 2 3 4 5 6 7 8 9 10]
How do I do this within MatLab?
Edit
I ran a test of the top three answers (Josh, Marc, & Kronos) and compared the time it took to run them. I ran each 100 times after doing a 10 iteration warmup. The vectors created were exactly the same size in length (16e+6) and were random values ranging from 1 to 100:
Test Results
Test: Total Time (100 runs): Avg Time Per Exec:
Josh B 21.3687 0.2137
Marc C 21.4273 0.2143
Kronos 31.1897 0.3119
It appears that both Josh's and Marc's solutions are similar in execution time.
a = [1 3 5 7 9];
b = [2 4 6 8 10];
temp = [a; b];
combined = temp(:)';
This can be done by the following:
a = [1 3 5 7 9];
b = [2 4 6 8 10];
combinedSize = size(a, 2) * 2;
combined(1:2:combinedSize) = a;
combined(2:2:combinedSize) = b;
This is obviously assuming that your vectors are exactly the same size. If by chance you want to merge two vectors that are not the same size then you can do the following:
combinedSize = max(size(a, 2), size(b, 2)) * 2;
combined = NaN(1,combinedSize);
combined(1:2:size(a,2)*2) = a;
combined(2:2:size(b,2)*2) = b;
This will place a NaN for the remaining elements of the smaller vector. For example, given the following sample vectors:
a = [1 3 5 7 9 11];
b = [2 4 6 8];
will result in the combined vector:
combined =
1 2 3 4 5 6 7 8 9 NaN 11 NaN
Place the vectors below eachother in a matrix and use reshape. For example:
>> A=[1 2 3]
A =
1 2 3
>> B=[4 5 6]
B =
4 5 6
>> C=reshape([A;B],1,size(A,2)+size(B,2))
C =
1 4 2 5 3 6
It's straightforward to generalize to more than 2 vectors.
You can also give a try to looping, for example:
a=[1 2 3 4 5];
b=[11 12 13 14 15];
for i = 1:N
{
if (i%2==0)
{ c[i] = b[i]; }
else
{ c[i] = a[i]; }
This shall work!
All the answers above only work if the two vectors have the same number of elements. The following will work even if they have different number of elements:
>>
A = [1 3 5];
B = [2 4 6 7 8];
C = [1 3 5 7 8];
D = [2 4 6];
AB = nan(1,2*max(numel(A),numel(B)));
CD = nan(1,2*max(numel(C),numel(D)));
AB(2*(1:length(A))) = A;
AB(1+2*(1:length(B))) = B;
CD(2*(1:length(C))) = C;
CD(1+2*(1:length(D))) = D;
>>
AB = AB(~isnan(AB))
CD = CD(~isnan(CD))
The result would be:
AB =
1 2 3 4 5 6 7 8
CD =
1 2 3 4 5 6 7 8