Write array into cell - arrays

I've been using Matlab for quite awhile but this one has got me--I want a one-liner that will take an array and write it into the indexed entries of a cell, e.g.
>> c = cell(1,6);
>> b = [1 2 3];
>> c{[2 4 6]} = b; %This doesn't actually work
>> disp(c)
[] [1] [] [2] [] [3]
I've tried all sorts of versions of this with num2cell, deal et al. but I can't find the magic bullet. Can it be done in a single assignment?

With mat2cell -
c([2 4 6]) = mat2cell(b,1,ones(1,numel(b)));
With num2cell -
c([2 4 6]) = num2cell(b);
Output -
>> disp(c)
[] [1] [] [2] [] [3]

Related

matlab find all cells containing each string in another cell array as fast as possible

Imagine you have two cell arrays
A={'a','b','b','c','d','e'}
B={'a','b','c','d','e','f'}
and you want to (as fast as possible) obtain a cell of the indexes of the shared elements
e.g.
{1,2,2,3,4,5} the indexes in B for the elements of A
{1,[2,3],4,5,6,[]} the indexes in A for the elements of B
how would you do it?
Here's how I would do it:
A = {'a','b','b','c','d','e'};
B = {'a','b','c','d','e','f'};
[~, ~, lab] = unique([A B]); % unique integer labels of elements in A and B
labA = lab(1:numel(A)); % this is A with each string replaced by its label
labB = lab(numel(A)+1:end); % this is B with each string replaced by its label
comp = bsxfun(#eq, labA(:), labB(:).'); % all pair-wise comparisons
[ii, jj] = find(comp); % row and column indices of the matchings
result_AinB = accumarray(ii, jj, [numel(A) 1], #(x){sort(x(:).')}); % group jj by ii
result_BinA = accumarray(jj, ii, [numel(B) 1], #(x){sort(x(:).')}); % group ii by jj
This gives
>> celldisp(result_AinB)
result_AinB{1} =
1
result_AinB{2} =
2
result_AinB{3} =
2
result_AinB{4} =
3
result_AinB{5} =
4
result_AinB{6} =
5
>> celldisp(result_BinA)
result_BinA{1} =
1
result_BinA{2} =
2 3
result_BinA{3} =
4
result_BinA{4} =
5
result_BinA{5} =
6
result_BinA{6} =
[]
Personally I would use
[c,ia,ib]=union(A,B)
or
[c,ia,ib]=intersect(A,B)
and handle the indices from these results. However this doesn't give the output in your requested format as it doesn't have the duplicates listed
ia = [1 2 3 4 5]
So to get it in your requested format use ismember twice.
Trial>> [~,ia]=ismember(A,B)
ia =
1 2 2 3 4 5
Trial>> [~,ib]=ismember(B,A)
ib =
1 2 4 5 6 0
Which is why I would use union or intersect as you can get all the required data from one call.
If you want it in that specific format then this should work
ia=cellfun(#(x) find(strcmp(x,A)),B,'UniformOutput',false)
ib=cellfun(#(x) find(strcmp(x,B)),A,'UniformOutput',false)
ia =
1×6 cell array
[1] [1×2 double] [4] [5] [6] [1×0 double]
ib =
1×6 cell array
[1] [2] [2] [3] [4] [5]

Find index of smallest element in an array not in another array (Matlab)

I have an array a = [6 8 2 1 9] and b = [1 2 6]. I want a function which returns 2 since a(2)=8 which is the smallest element of a not in b.
What I have tried so far:
[A,I] = sort(a);
index = I(find(~ismember(A,b),1))
I would like something faster as this piece of code has to run many times and the arrays involved are very large.
Thanks in advance!
Another (faster, I believe) solution would be:
a = [6 8 2 1 9];
b = [1 2 6];
[d,I] = setdiff(a,b); % d is the set difference, I is the indices of d elements in a
[m,J] = min(d); % m is the minimum in d, J is it's index
I(J) % This is the index of m in d (the value that you want)
ans =
2
Does this do what you need?
>> a = [6 8 2 1 9];
>> b = [1 2 6];
>> min(a(~ismember(a,b)))
ans =
8
Edit:
Oops - I meant
>> find(a==min(a(~ismember(a,b))),1)
ans =
2
This finds the index as you requested, rather than the value, which the first answer gives.

how to assemble vectors into matrix using for loop in MATLAB

I want to assemble a matrix from 5 vectors using a for loop in Matlab.
How can I do that? Or is there a simple alternative to do the same?
Here's an example: I have 5 vectors:
A = [1 2 3]
B = [1 2 3]
C = [1 2 3]
D = [1 2 3]
E = [1 2 3]
I want to create a matrix Z of size 3 x 5 from these vectors.
for loops are generally a bad idea in Matlab. Use vectorized syntax:
Z = [A;B;C;D;E]'; %'// vertical concatenation (5x3), then transpose to get 3x5
>> size(Z)
ans =
3 5
You can also transpose the vectors first and then concatenate them:
Z = [A' B' C' D' E']; %'// this comment is a syntax highlighting hotfix
>> size(Z)
ans =
3 5
If you really insist on using a for loop, here's how you would do that:
Z(3,5) = 0; %// preallocate a 3x5 numerical matrix
for i=1:3
Z(i,1) = A(i);
Z(i,2) = B(i);
Z(i,3) = C(i);
Z(i,4) = D(i);
Z(i,5) = E(i);
end
But it really makes no sense at all to do it this way...

Matlab, matrix of arrays

There are 3 matrices A,B,C:
A=[0 1;2 3]
B=[4 5;6 7]
C=[8 9;10 11]
How to create a new matrix D(2,2) so as its elements are arrays of a type
D = [{A(1,1), B(1,1), C(1,1)} {{A(1,2), B(1,2), C(1,12};
{A(2,1), B(2,1), C(2,1)} {A(2,2), B(2,2), C(2,2)}]
For example: Using an operator D(1,1) gives the result
0, 4, 8
The bracket {} are only illustrative and do not represent a matlab syntax...
You could stack the matrices along the third dimension:
D = cat(3,A,B,C);
Then you could access as:
>> D(1,1,:)
ans(:,:,1) =
0
ans(:,:,2) =
4
ans(:,:,3) =
8
if you want to get a 1D-vector:
>> squeeze(D(1,1,:)) %# or: permute(D(1,1,:),[1 3 2])
ans =
0
4
8
If you prefer to use cell arrays, here is an easier way to build it:
D = cellfun(#squeeze, num2cell(cat(3,A,B,C),3), 'UniformOutput',false);
which can be accessed as:
>> D{1,1}
ans =
0
4
8
You are almost there:
D = [{[A(1,1), B(1,1), C(1,1)]} {[A(1,2), B(1,2), C(1,2)]};
{[A(2,1), B(2,1), C(2,1)]} {[A(2,2), B(2,2), C(2,2)]}]
(you see the additional branches?)
D is now a cell array, with each cell containing a 1x3 matrix.
To access the cell array use this syntax:
D{1,1}

Element-wise array replication in Matlab

Let's say I have a one-dimensional array:
a = [1, 2, 3];
Is there a built-in Matlab function that takes an array and an integer n and replicates each
element of the array n times?
For example calling replicate(a, 3) should return [1,1,1,2,2,2,3,3,3].
Note that this is not at all the same as repmat. I can certainly implement replicate by doing repmat on each element and concatenating the result, but I am wondering if there is a built in function that is more efficient.
I'm a fan of the KRON function:
>> a = 1:3;
>> N = 3;
>> b = kron(a,ones(1,N))
b =
1 1 1 2 2 2 3 3 3
You can also look at this related question (which dealt with replicating elements of 2-D matrices) to see some of the other solutions involving matrix indexing. Here's one such solution (inspired by Edric's answer):
>> b = a(ceil((1:N*numel(a))/N))
b =
1 1 1 2 2 2 3 3 3
a = [1 2 3];
N = 3;
b = reshape(repmat(a,N,1), 1, [])
As of R2015a, there is a built-in and documented function to do this, repelem:
repelem Replicate elements of an array.
W = repelem(V,N), with vector V and scalar N, creates a vector W where each element of V is repeated N times.
The second argument can also be a vector of the same length as V to specify the number of replications for each element. For 2D replication:
B = repelem(A,N1,N2)
No need for kron or other tricks anymore!
UPDATE: For a performance comparison with other speedy methods, please see the Q&A Repeat copies of array elements: Run-length decoding in MATLAB.
>> n=3;
>> a(floor((0:size(a,2)*n-1)/n)+1)
ans =
1 1 1 2 2 2 3 3 3
Some exotic alternatives. Admittedly more funny than useful:
Assign the (first) result of meshgrid to a vector:
b = NaN(1,numel(a)*n); %// pre-shape result
b(:) = meshgrid(a,1:n);
Build a matrix that multiplied by a gives the result:
b = a * fliplr(sortrows(repmat(eye(numel(a)),n,1))).';
Use ind2sub to generate the indices:
[~, ind] = ind2sub([n 1],1:numel(a)*n);
b = a(ind);
If you have the image processing toolbox, there is another alternative:
N = 3;
imresize(a, [1 N*numel(a)],'nearest')
% To get b = [1 1 1 2 2 2 3 3 3]
N = 3;
a = [1 2 3];
temp_a = a(ones(N,1),:);
b = reshape(temp_a,1,numel(temp_a));
% To get b = [1 2 3 1 2 3 1 2 3]
N = 3;
a = [1 2 3];
temp_a = a(ones(N,1),:);
b = reshape(temp_a',1,numel(temp_a));

Resources