Matlab.Copying the rows n times in order [duplicate] - matlab

This question already has answers here:
A similar function to R's rep in Matlab [duplicate]
(4 answers)
Closed 9 years ago.
Hey I would like to do something like the following
A = [...
1 2 3
4 5 6
7 8 9]
to
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]
But please do not advice manual things. I am writing an algorithm with inputs and matrix dimensions may change.

There's a few ways. The simplest I think would be to use the Kronecker product:
B = kron(A, ones(3,1))
the faster but less readable solution is replication by multiplication and reshaping:
B = reshape((A(:) * ones(1,3))', 3*size(A,1),size(A,2))
or the same solution, but then using repmat:
B = reshape(repmat(A(:).',3,1), 3*size(A,1),size(A,2))

You can also try something based on the following:
a = [1 2 3]
b = [4 5 6]
c = [7 8 9]
d = [ a; a; b; b; c; c]
e = [ repmat([a], [2, 1]) ;
repmat([b], [2, 1]) ;
repmat([c], [2, 1]) ]
d and e both result in the matrix below:
=
1 2 3
1 2 3
4 5 6
4 5 6
7 8 9
7 8 9
To append more rows you can also use this for loop and see what the result is:
e = []
for i = 1:2
e = [ e;
repmat([a], [2, 1]) ;
repmat([b], [2, 1]) ;
repmat([c], [2, 1]) ]
end

Related

Find which matrix row has values specified from array

How can I find which row in a matrix has a specified set values that I entered in an array?
So for example;
A = [4 5 6 7;
8 4 5 6;
4 5 6 8;
8 4 8 9;
1 2 2 4;
5 3 4 6];
and I want to find which row has the vector of [4 5 6 8]
You can use a combination of all and find...
With implicit expansion (R2016b or newer)
find( all( A == [4 5 6 8], 2 ) )
Equivalently you can use bsxfun (compatible with all MATLAB versions)
find( all( bsxfun( #eq, A, [4 5 6 8] ), 2 ) )
The output in both cases is 3 from your example A.
I would go for #Wolfie's approach, assuming order matters.
Another possibility is to use ismember. This can be used both when order matters and when it doesn't. Let
A = [4 5 6 7; 8 4 5 6; 4 5 6 8; 8 4 8 9; 1 2 2 4; 5 3 4 6];
v = [4 5 6 8];
If order matters:
result = find(ismember(A, v, 'rows'));
If order doesn't matter:
result = find(all(ismember(A, v), 2));

Stacking matrices from a cell array on top of one another (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

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.

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

Extracting a 3x3 matrix from an image [duplicate]

This question already has an answer here:
How to divide a matrix into equals parts?
(1 answer)
Closed 9 years ago.
I need to extract a 3x3 matrix from an image and store it separately, and it should continue like this till the end of image. For example, my image is the following matrix:
p = [ 1 2 3 4 5 6 7 8 9; ...
1 2 3 4 5 6 7 8 9; ...
1 2 3 4 5 6 7 8 9; ...
1 2 3 4 5 6 7 8 9; ...
1 2 3 4 5 6 7 8 9; ...
1 2 3 4 5 6 7 8 9 ]
The output should be like this:
p1 = [1 2 3; 1 2 3; 1 2 3]
p2 = [4 5 6; 4 5 6; 4 5 6]
p3 = [7 8 9; 7 8 9; 7 8 9]
and so on....
Can you please suggest me code or a built-in function for this?
Simplest way to extract submatrices:
p1 = img(1:3, 1:3);
p2 = img(4:6, 4:6);
p3 = img(7:9, 7:9);
Function for doing slicing.
function imgsl = img_slice( img, ry, rx )
[ Y X ] = meshgrid(ry, rx);
imgsl = reshape(img(sub2ind(size(img),Y(:),X(:))),[length(rx) length(ry)]).';
Use it as follows:
p1 = img_slice( p, 1:3, 1:3 );
p2 = img_slice( p, 4:6, 4:6 );
p3 = img_slice( p, 7:9, 7:9 );
The image processing toolbox has a im2col function (link).
B = im2col(p, [3 3], 'distinct');
Then each column of B is a 3x3 block made into a vector, and you can use reshape(B(:, i), 3, 3) to recover the i-th 3x3 block. Note there are zeros padded to p.