Vectorize IF statement - matlab

I am trying to vectorize an if statement in Matlab and I am not sure how to do it. I want to assign a 'N' for positive values and 'S' for negative values. I want to avoid a for loop but here is my code:
LatDD = [23.0,12.3,-43.2,9.9,-40.7];
LatDir = ['' '' '' '' ''];
if (LatDD < 0)
LatDir = 'S'
else
LatDir = 'N'
end
Obviously this fails to do what I want because it really only checks the first element of LatDD. I could easily do a for loop but I want it to be vectorized. I tried logical indexing but all that got me was another vector with zeroes or ones which I would have to check with a for loop anyway.

You can use logical indexing here, you just have to do it twice
LatDD = [23.0,12.3,-43.2,9.9,-40.7];
LatDir = ['' '' '' '' ''];
LatDir(LatDD < 0) = 'S';
LatDir(LatDD >= 0) = 'N';
Since you have a binary choice here, you could even skip a step by prefilling LatDir with all 'N' and just changing the ones corresponding to negative LatDD values to 'S'
LatDD = [23.0,12.3,-43.2,9.9,-40.7];
LatDir = ['N' 'N' 'N' 'N' 'N'];
LatDir(LatDD < 0) = 'S';

Here's a one-liner -
char('S'*(LatDD<0) + 'N'*(~(LatDD<0)))
Sample run -
>> LatDD = [23.0,12.3,-43.2,9.9,-40.7];
>> LatDir = ['' '' '' '' ''];
>> char('S'*(LatDD<0) + 'N'*(~(LatDD<0)))
ans =
NNSNS

Related

using special characters in variable name Matlab

i have a function which returns a struct, and i want the return to have a meaningful names hence i wanted it to have names such as
sec.t<0.25
i.e t<0.25 being my variable and for this to return.
any help really appreciated.
function sec = sepfunc(intensdata)
lengthofdata=length(intensdata);
count1=0;
count_2=0;
count_3=0;
count_4=0;
count_5=0;
count_6=0;
count_7=0;
count_8=0;
for i= 1:lengthofdata %loop to seperate count number of data in 5 groups
if (intensdata(i,1)<0.025)
count1=count1+1;
elseif (intensdata(i,1)>=0.025 && intensdata(i,1)<0.05)
count_2=count_2+1;
elseif (0.05<=intensdata(i,1) && intensdata(i,1)<0.1)
count_3=count_3+1;
elseif (0.1<=intensdata(i,1) && intensdata(i,1)<0.125)
count_4=count_4+1;
elseif (0.125<=intensdata(i,1) && intensdata(i,1)<0.15)
count_5=count_5+1;
elseif (0.15<=intensdata(i,1) && intensdata(i,1)<0.175)
count_6=count_6+1;
elseif (0.175<=intensdata(i,1) && intensdata(i,1)<0.2)
count_7=count_7+1;
elseif (intensdata(i,1)>=0.2 )
count_8=count_8+1;
end
end
disp(count1);
disp(count_2);
disp(count_3);
disp(count_4);
disp(count_5);
disp(count_6);
disp(count_7);
disp(count_8);
j=1;
k=1;
l=1;
m=1;
n=1;
o=1;
p=1;
x=1;
low_sec=[count1];
lowmid_sec=[count_2];
middle_sec=[count_3];
upmid_sec=[count_4];
upper_sec=[count_5];
for i= 1:lengthofdata %to seperate original data into 5 different sub-groups.
if (intensdata(i,1)<0.05)
low_sec(j,1)=intensdata(i,1);
j=j+1 ;
elseif(0.05<=intensdata(i,1) && intensdata(i,1)<0.1)
lowmid_sec(k,1)=intensdata(i,1);
k=k+1;
elseif(0.1<=intensdata(i,1) && intensdata(i,1)<0.15)
middle_sec(m,1)=intensdata(i,1);
m=m+1;
elseif(0.15<=intensdata(i,1) && intensdata(i,1)<0.2)
upmid_sec(n,1)=intensdata(i,1);
n=n+1;
elseif( intensdata(i,1)>=0.2)
upper_sec(x,1)=intensdata(i,1);
x=x+1;
end
end
sec.low_sec = low_sec;
sec.lowmid_sec = lowmid_sec;
sec.middle_sec = middle_sec;
sec.upmid_sec = upmid_sec;
sec.upper_sec = upper_sec;
end
so i want to change low_sec to something like t<0.025 and 0.025
You cannot do this. Quoting from The MathWorks guidelines on variable names:
A valid variable name starts with a letter, followed by letters, digits, or underscores.
The < character is an operator. Most other programming languages don't allow this either. A suggestion would be to use the function name for the < operator: lt (help lt).
As you cannot put unusual characters in variable names I can see two ways to do this:
Descriptive: t_lt_0_025
Via a struct: s.name='t<0.025'

Matlab IF and ELSEIF loop

function final = fcn(sensor1, sensor2, sensor3)
% resolution = res
res = 10;
% value1 = ((sensor1+sensor2+sensor3)/3);
% | is used for 'or' command
if
sensor1 > res+sensor2 | sensor1> res+sensor3;
value1 = ((sensor2+sensor3)/2);
elseif
sensor2 > res+sensor1 | sensor2> res+sensor3;
value1 = ((sensor1+sensor3)/2);
elseif
sensor3 > res+sensor1 | sensor3> res+sensor2;
value1 = ((sensor1+sensor2)/2);
else
value1 = ((sensor1+sensor2+sensor3)/3);
end
final = value1;
I want it to display the final value based on the average. If any single value is greater than any of the other two by a certain number (resolution in this case) then it should neglect that number and just use the average of the other two. On matlab, my IF and ELSEIF loop has an error saying 'Parse error at , and Parse error at elseif.
You should have you if and your conditions on the same line. And no semi colon after the conditions:
.
.
.
if sensor1 > res+sensor2 || sensor1> res+sensor3
value1 = ((sensor2+sensor3)/2);
elseif sensor2 > res+sensor1 || sensor2> res+sensor3
value1 = ((sensor1+sensor3)/2);
.
.
.
btw you should be using || in this case because you're dealing with scalars.
You can get rid of almost all conditional statements with some vectorized approach. Additionally, it will automatically scale if you have many sensors as inputs with the same conditions.
Code
function value = fcn(sensor1, sensor2, sensor3)
res = 10;
sensor = [sensor1;sensor2;sensor3];
ind_first_cond_met = find(any(bsxfun(#gt,sensor,(res+sensor)'),2),1,'first');
if isempty(ind_first_cond_met)
value = mean(sensor);
else
sum_mat = bsxfun(#plus,sensor,sensor');
mean_every_other_two = [sum_mat(1,2) sum_mat(2,3) sum_mat(3,1)]./2;
value = mean_every_other_two(ind_first_cond_met);
end

Using switch statement and while loop in conjunction

I am trying to complete the following task:
Create
a
script
that
will
repeatedly
create
a
random
integer
K
in
the
range
of
0
to
20
until
every
case
has
been
entered
at
least
once.
You
have
3
possible
cases.
Case
A
is
entered
when
the
range
of
the
random
integer
K
is
between
or
equal
to
0
and
7.
Case
B
is
entered
when
the
range
of
the
random
integer
K
is
between
or
equal
to
8
and
14.
Case
C
is
entered
when
the
range
of
the
random
integer
K
is
between
or
equal
to
15
and
20.
Rules:
When
a
case
is
entered
you
must
print
to
the
user
“Congratulations
you
entered
Case
(A,
B,
or
C)”.
You
can
only
enter
each
case
once.
If
the
program
attempts
to
enter
the
same
case
more
than
once,
you
must
print.
“Invalid,
that
case
has
already
been
entered”.
The
program
will
end
once
all
the
cases
have
been
entered
and
the
program
will
print
“Good
job,
you
have
entered
all
cases”.
If
the
program
attempts
to
enter
any
already
entered
cases
more
than
3
times
(3
total
times
not
just
for
one
specific
case),
the
program
will
end
and
print
to
the
user
“That
random
generator
wasn’t
random
enough”.
Here is the code I have so fa. It has taken me a couple hours to debug. Am I approaching this the wrong way????Please let me know.
K = round(rand*(20))
flag = 0;
counterA =0;
counterB=0;
counterC=0;
switch K
case {0,1,2,3,4,5,6,7}
fprintf('Congratulations you entered Case A\n')
flag = 1;
counterA = 1
case {8,9,10,11,12,13,14}
fprintf('Congratulations you entered Case B\n')
flag =2;
counterB = 1
case {15,16,17,18,19,20}
fprintf ('Congratulations you entered Case C\n')
flag = 3;
counterC = 1
end
while flag == 1 || flag == 2 || flag ==3
K = round(rand*(20))
if K >=0 && K<=7 && flag==1
disp ('Invalid, that case has already been entered')
counterA = counterA+1
elseif K >=8 && K<=14 && flag ==2
disp ('Invalid, that case has already been entered')
counterB=counterB+1
elseif K >=15 && K<=20 && flag==3
disp ('Invalid, that case has already been entered')
counterC =counterC+1
elseif K >=0 && K<=7 && flag ~=1
counterA =counterA+1
flag == 1;
if counterA==1&&counterB~=2 ||counterA==1&&counterC~=2
fprintf('COngrats guacamole A\n')
end
elseif K >=8 && K<=14 && flag ~=2
counterB=counterB+1
flag == 2;
if counterB ==1&&counterA~=2||counterB==1&&counterC~=2
fprintf('COngratsavacado B\n')
end
elseif K >=15 && K<=20 && flag~=3
counterC=counterC+1
flag == 3;
if counterC==1&&counterA~=2||counterC==1&&counterB~=2
fprintf ('Congratscilantro C\n')
end
end
if counterA==1 && counterB==1 && counterC==1
flag=100;
disp('DONE')
elseif counterA == 3|| counterB==3 || counterC==3
disp ('That random generator wasnt random enough')
flag =99;
elseif counterA==2||counterB==2||counterC==2
disp('Inval')
end
Some words about your code:
Don't use variable names like counterA,counterB,counterC, use a array with 3 elements instead. In this case: You need only a total limit, thus one variable is enough.
rand*20 generates random values between 0 and 20, but using round(rand*20) causes a lower probability for 0 and 20. Use randi if you need integers.
Use "Start indent" to format your code clean, it makes it easier to read.
This is not a full solution, the part with the 3 errors is missing. I think you will get this on your own.
caseNames={'A','B','C'};
caseEntered=[false,false,false];
%while there exist a case which is not entered and limit is not reached, continue
while ~all(caseEntered)
K = randi([0,20]);
switch K
case {0,1,2,3,4,5,6,7}
cs=1;
case {8,9,10,11,12,13,14}
cs=2;
case {15,16,17,18,19,20}
cs=3;
end
if caseEntered(cs)
%case has previously been entered, tdb
else
%case is entered frist time
fprintf('Congratulations you entered Case %s\n',caseNames{cs});
caseEntered(cs)=true;
end
end

Deleting rows with specific rules

I got a 20*3 cell array and I need to delete the rows contains "137", "2" and "n:T"
Origin data:
'T' '' ''
'NP(*)' '' ''
[ 137] '' ''
[ 2] '' ''
'ARE' 'and' 'NP(FCC_A1#1)'
'' '' '1:T'
[ 1200] [0.7052] ''
[1.2051e+03] [0.7076] ''
'ARE' 'and' 'NP(FCC_A1#3)'
'' '' '2:T'
[ 1200] [0.0673] ''
[1.2051e+03] [0.0671] ''
'ARE' 'and' 'NP(M23C6)'
'' '' '3:T'
[ 1200] [0.2275] ''
[1.2051e+03] [0.2253] ''
[ 137] '' ''
[ 2] '' ''
And I want it to be like
'T' '' ''
'NP(*)' '' ''
'ARE' 'and' 'NP(FCC_A1#1)'
[ 1200] [0.7052] ''
[1.2051e+03] [0.7076] ''
'ARE' 'and' 'NP(FCC_A1#3)'
[ 1200] [0.0673] ''
[1.2051e+03] [0.0671] ''
'ARE' 'and' 'NP(M23C6)'
[ 1200] [0.2275] ''
[1.2051e+03] [0.2253] ''
I've tried regexp and strcmp and they don't work well. Plus the cell array also hard to deal with. Can anyone help?
Thank you in advance.
If you can somehow read your original data so that all cells are strings or empty arrays (not numeric values), you can do it with strcmp and regexprep:
% The variable 'data' is a 2D-cell array of strings or empty arrays
datarep = regexprep(data,'^\d+:T','2'); % replace 'n:T' with '2' for convenience
remove1 = strcmp('2',datarep); % this takes care of '2' and 'n:T'
remove2 = strcmp('137',datarep); % this takes care of '137'
rows_keep = find(~sum(remove1|remove2,2)); % rows that will be kept
solution = data(rows_keep,:)
For example, with this data
'aa' 'bb' 'cc'
'dd' 'dd' '2'
'137' 'dd' 'dd'
'dd' 'dd' '11:T'
'1:T' '1:137' 'dd'
'dd' '' []
the result in the variable solution is
'aa' 'bb' 'cc'
'dd' '' []
I just tried the following codes on my desktop and it seems to do the trick. I made a as the cell array you had.
L = size(a, 1);
mask = false(L, 1);
for ii = 1:L
if isnumeric(a{ii, 1}) && (a{ii, 1} == 137 || a{ii, 1} == 2)
mask(ii) = true;
elseif ~isempty(a{ii, 3}) && strcmp(a{ii, 3}(end-1:end), ':T')
mask(ii) = true;
end
end
b = a(~mask, :)
Now, b should be the cell array you wanted. Basically, I created a logical mask that indicates the position of rows that satisfy the rules, then use the inverse of it to call out the rows.
Here is another simple option:
%Anonymous function that checks if a cell is equal to 173 or to 2 or fits the '*:T*' pattern
Eq137or2 = #(x) sum(x == 137 | x == 2) | sum(strfind(num2str(x), ':T') > 1)
%Use the anonymous functions to find the rows you don't want
mask = = sum(cellfun(Eq137or2, a),2)
%Remove the unwanted rows
a(~mask, :)

how to store looping data in a single array or matrix?

i have a program with nested loop. i want all the values after each loop is completed, to
be stored in a single matrix A or array A.
display should be like
A= value1
value2
value3
etc...
where value1,value2,value3 are answers got at the end of each loop.
here is the program
load('b2.txt');
[M,N]=size(b2);
amp=[1.75,2,2.25,2.5,2.75,3,3.25,3.5,3.75,4];
%defining threshold
m=10501;
for i=10575:75:21000
a=b2(m:i,:);
time=b2(i,2)
t=40;
sum1=0;
sum2=0;
sum3=0;
sum4=0;
sum5=0;
sum6=0;
sum7=0;
sum8=0;
sum9=0;
sum10=0;
for R=1:75
if (a(R,3)>=t) && (a(R,3)<t+5)
sum1=sum1+a(R,1);
elseif (a(R,3)>=t+5) && (a(R,3)<t+10)
sum2=sum2+a(R,1);
elseif (a(R,3)>=t+10) && (a(R,3)<t+15)
sum3=sum3+a(R,1);
elseif (a(R,3)>=t+15) && (a(R,3)<t+20)
sum4=sum4+a(R,1);
elseif (a(R,3)>=t+20) && (a(R,3)<t+25)
sum5=sum5+a(R,1);
elseif (a(R,3)>=t+25) && (a(R,3)<t+30)
sum6=sum6+a(R,1);
elseif (a(R,3)>=t+30) && (a(R,3)<t+35)
sum7=sum7+a(R,1);
elseif (a(R,3)>=t+35) && (a(R,3)<t+40)
sum8=sum8+a(R,1);
elseif (a(R,3)>=t+40) && (a(R,3)<t+45)
sum9=sum9+a(R,1);
elseif (a(R,3)>=t+45) && (a(R,3)<t+50)
sum10=sum10+a(R,1);
end
cumulative_hits=[sum1,sum2,sum3,sum4,sum5,sum6,sum7,sum8,sum9,sum10];
for count=1:10
if cumulative_hits(1,count)<= 0
amplitude(1,count)= 0;
else
amplitude(1,count)=amp(1,count);
end
end
cumulative_hits(cumulative_hits==0)=[];
amplitude(amplitude==0)=[];
y=log10(cumulative_hits);
p=polyfit(amplitude,y,1);
f=polyval(p,amplitude);
end
%disp(p(1,1))
abs(p(1))
m=m+75;
end
need this asap.. thanks :)
You need to provide informations about which variable to store in the resulting array A, but just for your information:
You can always easily append values to it via:
A = [A; new_value];
which works either if new_value is a scalar or if it's a column-vector with identical number of elements like number of columns of A