Storing data in matrix in for and if loops - matlab

I have a problem in storing the data in matrix in for and if loops,
The results give me only the last value of the last iteration. I want all the
results of all iterations to be stored in a matrix be sequence.
Here is a sample of my code:
clear all
clc
%%%%%%%%%%%%%%
for M=1:3;
for D=1:5;
%%%%%%%%%%%%%%
if ((M == 1) && (D <= 3)) || ((M == 3) && (2 <= D && D <= 5))
U1=[5 6];
else
U1=[0 0];
end
% desired output:
% U1=[5 6 5 6 5 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 5 6 5 6 5 6]
%%%%%%%%%%%%%%
if (M == 1) && (D==4) || ((M == 3) && (D == 1))
U2=[8 9];
else
U2=[0 0];
end
% desired output:
% U2=[0 0 0 0 0 0 8 9 0 0 0 0 0 0 0 0 0 0 0 0 8 9 0 0 0 0 0 0 0 0]
%%%%%%%%%%%%%%
if ((M == 1) && (D == 5)) || ((M == 2) && (1 <= D && D <= 5))
U3=[2 6];
else
U3=[0 0];
end
% desired output:
% U3=[0 0 0 0 0 0 0 0 2 6 2 6 2 6 2 6 2 6 2 6 0 0 0 0 0 0 0 0 0 0]
%%%%%%%%%%%%%%
end
end

You are overwriting your matrices each time you write UX=[X Y];.
If you want to append data, either preallocate your matrices and specify the matrix index each time you assign a new value, or write UX=[UX X Y]; to directly append data at the end of your matrices.
clear all
clc
U1=[];
U2=[];
U3=[];
for M=1:3
for D=1:5
if ((M == 1) && (D <= 3)) || ((M == 3) && (2 <= D && D <= 5))
U1=[U1 5 6];
else
U1=[U1 0 0];
end
% desired output:
% U1=[5 6 5 6 5 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 5 6 5 6 5 6]
if (M == 1) && (D==4) || ((M == 3) && (D == 1))
U2=[U2 8 9];
else
U2=[U2 0 0];
end
% desired output:
% U2=[0 0 0 0 0 0 8 9 0 0 0 0 0 0 0 0 0 0 0 0 8 9 0 0 0 0 0 0 0 0]
if ((M == 1) && (D == 5)) || ((M == 2) && (1 <= D && D <= 5))
U3=[U3 2 6];
else
U3=[U3 0 0];
end
% desired output:
% U3=[0 0 0 0 0 0 0 0 2 6 2 6 2 6 2 6 2 6 2 6 0 0 0 0 0 0 0 0 0 0]
end
end

You can avoid the loops altogether:
[M,D] = meshgrid(1:3,1:5);
M = M(:)'; D = D(:)';
idx1 = ( M==1 & D<=3 ) | ( M== 3 & 2<=D & D<=5 );
idx2 = ( M==1 & D==4) | ( M==3 & D==1 );
idx3 = ( M==1 & D==5 ) | ( M==2 & 1<=D & D<=5 );
U1 = bsxfun(#times, idx1, [5;6]); U1 = U1(:)';
U2 = bsxfun(#times, idx2, [8;9]); U2 = U2(:)';
U3 = bsxfun(#times, idx3, [2;6]); U3 = U3(:)';

Related

Create a Function which returns -1 for empty matrix, 0 for scalar, 1 for vector, 2 for none of these

I am not allowed to use isempty, isscalar, or isvector.
My code is :
function a = classify(x)
b = sum(x(:));
c = sum(b);
if c == 0
a = -1;
elseif length(x) == 1
a = 0;
elseif length(x) > 1
a = 1;
else
a = 2;
end
I am getting error with input :
0 1 0 0 0 1 1
1 0 0 1 1 0 0
1 1 0 0 1 1 1
0 1 1 1 1 1 0
0 1 0 1 0 1 0
1 0 0 1 1 1 1
0 1 0 0 0 0 1
Output for above input is 1
My Auto grader is giving the following error:
Feedback: Your function made an error for argument(s) [0 1 0 0 0 1 1;1 0 0 1 1 0 0;1 1 0 0 1 1 1;0 1 1 1 1 1 0;0 1 0 1 0 1 0;1 0 0 1 1 1 1;0 1 0 0 0 0 1]
Your solution is not correct.
If you are allowed to use size, then a possible solution is
function R = classify(data)
S = size(data);
if any(S == 0) % There is at least one dimension that is zero
R = -1;
elseif all(S == 1) % All dimensions are equal to 1
R = 0;
elseif sum(~(S == 1)) == 1 % There is exactly one dimension that contains more than 1 element
R = 1;
else % There are more than 1 dimensions with more than 1 element
R = 2;
end
end

In matlab, increment different column element for every row in without using a loop

Assume you have an 4x4 matrix A of zeros:
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
And an 4x1 vector B that represents column indices for matrix A (so values [1:4])
4
2
3
1
Now I want to increment those columnpositions in matrix A on the index on every row from vector B.
I have tried a couple of constructions myself but can't quite manage to do this.
For example I tried:
A(:, B) = A(:, B)+1
Which just increment every element in A.
This is how I want the operation to act:
>> A(somethting(B)) = A(somethting(B)) + 1
0 0 0 1
0 1 0 0
0 0 1 0
1 0 0 0
You can do this by using the linear index to each of the elements you want to address. Compute this using sub2ind:
>> A = zeros(4)
A =
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
>> B = [4 2 3 1]
B =
4 2 3 1
>> i=sub2ind(size(A),B,1:4)
i =
4 6 11 13
>> A(i) = A(i)+1
A =
0 0 0 1
0 1 0 0
0 0 1 0
1 0 0 0
Well just in case you want a looped version :p
A = zeros(4,4);
B = [4, 2, 3, 1];
for i = 1:length(B)
A(i, B(i) ) = A(i, B(i) ) + 1;
end
A = zeros(4);
B = [4 2 3 1];
A(repmat([1:4]',1,4) == repmat(B,4,1)) = 1
A =
0 0 0 1
0 1 0 0
0 0 1 0
1 0 0 0

Count numbers of consecutive 1s and 0s in a vector

In Matlab I have a vectors that looks like this:
0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 0 1 0 1
What I want to do now is to count the number of 1 in this vector. Consecutive 1s count as 1. Additionally, I want also to calculate the average and median numbers of 0s between 1s. So for this example:
1s: 5
Median 0s: 3.5
Average 0s: 3
I solved that with a brute force method, that is investigate each element in a loop and check the previous as well as the next element. But I'm sure there has to be a solution that is way faster. Any idea?
Given the data in vector v,
v = [ 0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 0 1 0 1 ]; % data
compute as follows:
w = [ 1 v 1 ]; % auxiliary vector
runs_zeros = find(diff(w)==1)-find(diff(w)==-1); % lenghts of runs of 0's
% Desired results:
number_ones = length(runs_zeros)-1+v(1)+v(end);
% For average and median, don't count first run if v(1) is 0,
% or last run if v(end) is 0:
average_runs_zeros = mean(runs_zeros(2-v(1):end-1+v(end)));
median_runs_zeros = median(runs_zeros(2-v(1):end-1+v(end)));
This is faster than #TryHard's solution because it doesn't require converting to strings
Okay, so this seems to be working
>> a=[0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 0 1 0 1];
>> %Remove traling and leading zeros
>> y = a(find(a,1,'first'):find(a,1,'last'));
>> q = diff([0 a 0] == 1);
>> v = find(q == -1) - find(q == 1);
>> length(v) % Consecutive Ones
ans =
5
>> q = diff([0 ~y 0] == 1);
>> v = find(q == -1) - find(q == 1);
>> v
v =
3 4 4 1
>> median(v)
ans =
3.5000
>> mean(v)
ans =
3
You can do it as follows:
dat=[0 0 1 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 0 1 0 1];
str = regexprep(num2str(dat),' ','');
[n1 istart1 iend1] = regexp(str,'[1]+','match','start','end');
[n0 istart0 iend0] = regexp(str(min(istart1):max(iend1)),'[0]+','match','start','end');
% number of strings of `1`s
length(n1)
% property of intercalated strings of `0`s
median([iend0-istart0+1])
mean([iend0-istart0+1])

Indexing of 2D array in matlab

I have a 6X4 matrix M1 containing only zeros.
I also have two 1D arrays Y1 and Y2 each with length 4.The two arrays contain the desired index values. Now, I want to set(convert to 1) the elements of matrix M1 such that
M1(Y1:Y2) is equal to 1
for ex: Y1=[1 2 2 1] and Y2=[3 4 5 3]
then, M1 should be
1 0 0 1
1 1 1 1
1 1 1 1
0 1 1 0
0 0 1 0
0 0 0 0
I can do this using for loop. But is there any optimised way to do it? (I intend to use much bigger matrices)
use cumsum!
>> szM = size(M1);
>> M1( sub2ind( szM, Y1, 1:szM(2) ) ) = 1
M1 =
1 0 0 1
0 1 1 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
>> M1( sub2ind( szM, Y2+1, 1:szM(2) ) ) = -1
M1 =
1 0 0 1
0 1 1 0
0 0 0 0
-1 0 0 -1
0 -1 0 0
0 0 -1 0
>> M = cumsum(M,1)
M =
1 0 0 1
1 1 1 1
1 1 1 1
0 1 1 0
0 0 1 0
0 0 0 0
A pitfall:
If any of Y2 equals 6 than setting Y2+1 to -1 will exceed matrix dimension.
To fix this you can add two lines before setting to -1 the elements of M:
>> cols = 1:szM(2);
>> sel = Y2 < szM(1);
>> M1( sub2ind( szM, Y2(sel)+1, cols(sel) ) ) = -1
A spin-off for Pavan Yalamanchili's answer using bsxfun: (hover to see:)
using bsxfun without offsets:
M1 = bsxfun( #ge, (1:size(M1,1))', Y1 ) & bsxfun( #le, (1:size(M1,1))', Y2 );
There may be other techniques, but this uses element wise operations which are insanely parallel.
A very simple solution. Thanks #Shai
>> [rows, cols] = size(M);
>> Y1=[1 2 2 1]; Y2=[3 4 5 3];
>> M = bsxfun(#ge, (1:rows)', Y1) & bsxfun(#le, (1:rows)', Y2)
M =
1 0 0 1
1 1 1 1
1 1 1 1
0 1 1 0
0 0 1 0
0 0 0 0
Unnecessarily complicated code
[rows, cols] = size(M);
offsets = ((1 : cols) - 1) * rows
Y1 = offsets + Y1;
Y2 = offsets + Y2;
M = reshape(1:numel(M), rows, cols);
M = bsxfun(#ge, M, Y1) & bsxfun(#le, M, Y2);

Create a matrix with sequencial values padded with zeros (without loops)

I have two matrices aand b of 1 column and n rows.
These matrices represent min and max values.
From these I need to create a n by m matrix.
m is the max value of [a ; b]
The result must contain each value between a(:) and b(:), padded with zeros.
note: it's easy to do with a for loop, but I want to avoid loops.
Exemple :
Starting with these two matrices :
>> a = [3 ; 5 ; 2 ; 7 ; 4]
a =
3
5
2
7
4
>> b = [7 ; 7 ; 5 ; 8 ; 4]
b =
5
7
4
8
4
I want to end with this matrix :
result =
3 4 5 6 7 0 0 0
5 6 7 0 0 0 0 0
2 3 4 5 0 0 0 0
7 8 0 0 0 0 0 0
4 0 0 0 0 0 0 0
So far I have this :
>> result = zeros(size(a,1), max([a ; b]));
>> rows = [1:size(a,1)]
rows =
1 2 3 4 5
>> index = sub2ind(size(result), rows, b - a + 1)
>> result(index) = b
result =
0 0 0 0 7 0 0 0
0 0 7 0 0 0 0 0
0 0 0 5 0 0 0 0
0 8 0 0 0 0 0 0
4 0 0 0 0 0 0 0
>> result(:,1) = a
result =
3 0 0 0 7 0 0 0
5 0 7 0 0 0 0 0
2 0 0 5 0 0 0 0
7 8 0 0 0 0 0 0
4 0 0 0 0 0 0 0
I'd solve this with a simple loop, which is also probably the fastest solution
a = [3 ; 5 ; 2 ; 7 ; 4]
b = [7 ; 7 ; 5 ; 8 ; 4]
nSteps = b-a+1;
nRows = size(a,1);
result = zeros(nRows, max([a ; b]));
for iRow = 1:nRows
result(iRow,1:nSteps(iRow)) = a(iRow):b(iRow);
end
result =
3 4 5 6 7 0 0 0
5 6 7 0 0 0 0 0
2 3 4 5 0 0 0 0
7 8 0 0 0 0 0 0
4 0 0 0 0 0 0 0
In case you don't need readability, here's a non-loop solution:
result = ones(nRows, max([a ; b]));
result(:,1) = a;
result = cumsum(result,2);
result(bsxfun(#gt,result,b))=0
result =
3 4 5 6 7 0 0 0
5 6 7 0 0 0 0 0
2 3 4 5 0 0 0 0
7 8 0 0 0 0 0 0
4 0 0 0 0 0 0 0
Some problems aren't worth the effort of vectorising:
a = [3 ; 5 ; 2 ; 7 ; 4];
b = [7 ; 7 ; 5 ; 8 ; 4];
cols = max(max(a),max(b))
result = zeros(length(a),cols)
for i = 1:length(a)
A = a(i):b(i)
result(i,:) = padarray(A, [0 cols-length(A)], 0, 'post');
end