Cell array manipulation matlab - matlab

I need elements from the last cell (say k-th) not occurring in cell before it i.e. (k-1)th cell where k = 1,2,...,p. An example, k=2, r=2^(k+2)+2, n=2^(k)+1;
for i=1:k
dt = 1:2^i:n;
for j=1:2^(k-i)+1
cd(j,:)= dt+ r*(j-1);
end
dd{i}=cd;
clear cd
end
dd{1} =[1 3 5; 11 13 15; 21 23 25]
dd{2} = [1 5;21 25]
I want all entries occurring in dd{2} removed from dd{1} i.e.
dd{1}= [3 11 13 15 23].
dd{2}= [1 5;21 25]

I think you can use setdiff to achieve your goal (difference of two arrays):
setdiff([1,2,3,4,5],[3,4])
ans =
1 2 5

Related

Repeat row vector as matrix with different offsets in each row

I want to repeat a row vector to create a matrix, in which every row is a slightly modified version of the original vector.
For example, if I have a vector v = [10 20 30 40 50], I want every row of my matrix to be that vector, but with a random number added to every element of the vector to add some fluctuations.
My matrix should look like this:
M = [10+a 20+a 30+a 40+a 50+a;
10+b 20+b 30+b 40+b 50+b;
... ]
Where a, b, ... are random numbers between 0 and 2, for an arbitrary number of matrix rows.
Any ideas?
In Matlab, you can add a column vector to a matrix. This will add the vector elements to each of the row values accordingly.
Example:
>> M = [1 2 3; 4 5 6; 7 8 9];
>> v = [1; 2; 3];
>> v + M
ans =
2 3 4
6 7 8
10 11 12
Note that in your case v is a row vector, so you should transpose it first (using v.').
As Sardar Usama and Wolfie note, this method of adding is only possible since MATLAB version R2016b, for earlier versions you will need to use bsxfun:
>> % instead of `v + M`
>> bsxfun(#plus, v, M)
ans =
2 4 6
5 7 9
8 10 12
If you have a MATLAB version earlier than 2016b (when implicit expansion was introduced, as demonstrated in Daan's answer) then you should use bsxfun.
v = [10 20 30 40 50]; % initial row vector
offsets = rand(3,1); % random values, add one per row (this should be a column vector)
output = bsxfun(#plus,offsets,v);
Result:
>> output =
10.643 20.643 30.643 40.643 50.643
10.704 20.704 30.704 40.704 50.704
10.393 20.393 30.393 40.393 50.393
This can be more easily understood with less random inputs!
v = [10 20 30 40 50];
offsets = [1; 2; 3];
output = bsxfun(#plus,offsets,v);
>> output =
11 21 31 41 51
12 22 32 42 52
13 23 33 43 53
Side note: to get an nx1 vector of random numbers between 0 and 2, use
offsets = rand(n,1)*2

How to ge the average of two matrices on Matlab?

I have 2 matrices,
a= [1 2 3; 4 5 6; 7 8 9; 10 11 12];
and
b= [13 14 15; 16 17 18; 19 20 21; 22 23 24];
How can I make the average of these 2 matrices and store the values in another matrix "C" on Matlab?
The value of C will be,
c= [(1+13)/2 (2+14)/2 (3+15)/2; (4+16)/2 (5+17)/2 (6+18)/2;...]
Thanks.
You would do:
c = (a+b)/2
This will give you the desired result.
Another way would be to stack the matrices on top of each other in 3D, then find the average along the third dimension:
c = mean(cat(3, a, b), 3);

Search particular matrix in cell array

So, I have this cell array contains n x 2 matrix in each cell. Here is the sample data :
[16 17;17 17]
<6x2 double>
<52x2 double>
[17 17;17 18]
[17 18;17 17]
What I am going to do is eliminate the duplicated matrix (matrices with same values or reversed values). in this case is [17 18; 17 17] (5th row), because we already have [17 17; 17 18] (4th row)
I tried using unique function but it says that the function just worked for strings. I also tried to find it with cellfun like this
cellfun(#(x) x==whatToSearch, lineTraced, 'UniformOutput', false)
but it says 'Matrix dimension must agree'
Thanks in advance.
Here is a solution. Given a m x 1 column cell array C of matrices, this code deletes the equivalent duplicates. (Here it will delete the 4th and 5th matrices, which are equivalent to the 1st).
C{1} = magic(3);
C{2} = magic(4);
C{3} = magic(5);
C{4} = C{1};
C{5} = flipud(C{1});
myEq = #(A,B) isequal(A,B) | isequal(A,flipud(B)); %// equivalence operator tests for same or up-down flipped matrix
C = C(:); %// ensure the cell array is a column
Crep = repmat(C,1,size(C,1)); %// repeat cell array along rows to get a square
comp = cellfun(myEq,Crep,Crep'); %'//get a comparison matrix by comparing with transpose
comp = tril(comp) - eye(size(comp)); %// ignore upper triangle and diagonal
idx = find( sum(comp,2)==0 ); %// get index of matrices we want to keep
result = C(idx); %// get result
The output is deletes the 4th and 5th matrices, leaving the first three magic matrices:
>> result
result =
[3x3 double] [4x4 double] [5x5 double]
>> result{1}, result{2}, result{3}
ans =
8 1 6
3 5 7
4 9 2
ans =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
ans =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
Here's code that does what you want.
mydup = rand(5,2);
mycell = {mydup;mydup;rand(7,2);rand(3,2);rand(5,2)}
myNewCell = trimCell(mycell)
Where trimCell is the function below:
function myNewCell = trimCell(myCell)
exclude = false(size(myCell));
for iter = 1:size(myCell,1)
toCompare = myCell{iter};
comparisons = cellfun(#(x) all(size(x)==size(toCompare)) && myEquals(x, toCompare),myCell);
% comparisons has at least 1 true in it, because toCompare==toCompare
exclude(iter) = sum(comparisons)>1;
end
myNewCell = myCell(~exclude);
end
function boolValue = myEquals(x,y)
assert(all(size(x)==size(y)));
boolValue = true;
for iter = 1:size(x,1)
thisRow = all(sort(x(iter,:))==sort(y(iter,:)));
boolValue = boolValue && thisRow;
if ~boolValue
return
end
end
end
Basically, what this function does, is, for each matrix in the cell it checks first if the sizes are equal. If the sizes aren't equal, then we know the matrices aren't equal, even if we reorder the rows.
If they are the same size, then we need to check if they're equal after row reordering. That's accomplished by the function myEquals which goes through row by row and sorts the rows before comparing them. It exits with false on the first row it finds that is not equal after reordering.
Hope this helps,
Andrew

Finding middle point for consecutive number

Let say I have
A=[1 3 4 5 6 7 9 12 15 16 17 18 20 23 24 25 26];
My interest is how to find the middle value between consecutive numbers using Matlab.
For example, first group of consecutive numbers is
B=[3 4 5 6 7];
so the answer should be is 5. The 2nd group of consecutive numbers (i.e. [15 16 17 18]) should give 16 etc...
At the end, my final answer is
[5 16 24]
Here is a vectorized approach:
d = [diff(A) == 1, 0];
subs = cumsum([diff(d) == 1, 0]).*(d | [0, diff(d) == -1]) + 1
temp = accumarray(subs', A', [], #median)
final = floor(temp(2:end))
Here is some sample code which does what you are looking for. I'll let you play with the different outputs to see what they do exactly, although I wrote some comments to follow:
clear
clc
A=[1 3 4 5 6 7 9 12 15 16 17 18 20 23 24 25 26]
a=diff(A); %// Check the diff array to identify occurences different than 1.
b=find([a inf]>1);
NumElements=diff([0 b]); %//Number of elements in the sequence
LengthConsec = NumElements((NumElements~=1)) %// Get sequences with >1 values
EndConsec = b(NumElements~=1) %// Check end values to deduce starting values
StartConsec = EndConsec-LengthConsec+1;
%// Initialize a cell array containing the sequences (can have ifferent
%lengths, i.e. an array is not recommended) and an array containing the
%median values.
ConsecCell = cell(1,numel(LengthConsec));
MedianValue = zeros(1,numel(LengthConsec));
for k = 1:numel(LengthConsec)
ConsecCell{1,k} = A(StartConsec(k):1:EndConsec(k));
MedianValue(k) = floor(median(ConsecCell{1,k}));
end
%//Display the result
MedianValue
Giving the following:
MedianValue =
5 16 24
diff + strfind based approach -
loc_consec_nums = diff(A)==1 %// locations of consecutive (cons.) numbers
starts = strfind([0 loc_consec_nums],[0 1]) %// start indices of cons. numbers
ends = strfind([loc_consec_nums 0],[1 0]) %// end indices of cons. numbers
out = A(ceil(sum([starts ; ends],1)./2))%// median of each group of starts and ends
%// and finally index into A with them for the desired output

simple sliding window filter in Matlab

I don't have the package for nlfilter and I didn't quite follow this example.
I have a really simple function fun and I want to apply it to a moving window of an array. The array is Nx1, and I want to look at length k intervals, say. So for N=10 and k=3 and fun = #(x) min(x); I would get
A = [13 14 2 14 10 3 5 9 15 8];
filter(A,k,fun) = [2 2 2 3 3 3 5 8];
Here I only want to look at indices 1,2,3 then 2,3,4 then ... then 8,9,10, so the final sequence is length 7. I can do this easy with a for loop, but I have no idea how to vectorize it for Matlab. Help, please. Thanks.
Here is one very simple and fast way to do it:
>> min([A(1:(end-2)); A(2:(end-1)); A(3:end)], [], 1)
ans =
2 2 2 3 3 3 5 8
EDIT: Since you want a full function...
function running_min = running_min(x, k)
xrep = repmat(x, 1, k);
xrep = reshape([xrep zeros(1, k)], length(x)+1, k);
running_min = min(xrep, [], 2)';
running_min = running_min(1:end-k);
The post you mentioned gave a general solution for building sliding windows (you could control: overlapping vs. distinct, slide step, overlap amount, windows size)
In your case, it is much simpler and can be easily performed with the HANKEL function:
x = [13 14 2 14 10 3 5 9 15 8];
idx = hankel(1:3, 3:length(x))
min( x(idx) )
If you want to build a reusable solution:
function y = myFilter(x,k,fcn)
idx = hankel(1:k, k:length(x));
y = cellfun(fcn, num2cell(x(idx),1));
end
which we use as:
x = [13 14 2 14 10 3 5 9 15 8];
y = myFilter(x, 3, #(x)min(x))
Note I am using CELLFUN in case fcn cannot operate across dimensions in a vectorized manner...