A3 Logical expressions, indexing, and flow control
Logical expressions ask a yes/no or true/false question, and are often used as a way to allow us to make alternate computations based on if some condition is true or false. For example, suppose we want to add the two elements of a 1x2 matrix if the first element is between +10 and -10, and subtract the two elements if it is not. This is accomplished via the if...else...end statement sequence:
>> v=[5 6];
>> if abs(v)<10
sum(v)
else
diff(v)
end
Logical expressions are also used to select elements of a matrix via a form of indexing, called logical indexing. With logical indexing, we write an expression that is true or false at each index of the matrix, and treat the list of yes/no logical outputs (one for each index) as the selected (yes/true) and non-selected (no/false) indices.
b=rand(10,1);
tf=b>.5;
x=b(tf)
Or we can nest the previous two expressions:
y=b(b>.5)
We can also use logical indexing to change elements of the original matrix:
mean(b)
b(b>.9)=0;
mean(b)
Cell arrays are particularly useful when you want a single variable to hold data, but are not sure if the same amount of data will be put into each element of the array. For example, let’s say you have an experiment involving a questionnaire, and you want to compute the average age of each participant who answered one of the questions (on a 5-point rating scale) with a 1, 2, 3, etc. Since there will not be an equal number of participants answering the question with a 1, 2, etc., you will end up with an uneven number of ages in each of the 5 groups. When inputting the data, you could create separate variables for each of the groups, but this will make life more difficult later on when writing for-loops. Instead, it will be better to put the data into a 1x5 cell:
dat=[randi(5,[1000 1]) randi([18 50],[1000 1])];
dat={dat(dat(:,1)==1,2), ...
dat(dat(:,1)==2,2), ...
dat(dat(:,1)==3,2), ...
dat(dat(:,1)==4,2), ...
dat(dat(:,1)==5,2)};
You can see that there are different numbers of elements in the cell array. Now if you want to compute the median age of each group, you will want to step through each element of the cell array in turn, and compute the median for each. To do this, we need a method of performing that ‘stepping-through’ operation. This is the purpose of the two flow control sequences we will use, the for-loop and the while-loop. The for-loop runs through a sequence of expressions a pre-selected number of times, whereas the while-loop runs through a sequence of expressions until a logical expression becomes false. We will compute the medians of the dat cell array using both of these. Using a for-loop this is:
meds=zeros(1,5);
for i=1:length(dat),
meds(i)=median(dat{i});
end
and using the while-loop it is:
meds=zeros(1,5); i=0;
while i<length(dat), i=i+1;
meds(i)=median(dat{i});
end
We can expand each of these loops to have them tell us about the iteration as it is happening. In the for-loop we can have it output the value of i so we can see that the statement after the word ‘for’ creates an automatic iteration of the variable i, starting at the value 1 and ending at the value 5 (which is the length of the dat variable). In the while-loop we can add the output of the logical condition, i<length(dat), so we can see when it changes to ‘false’ and therefore kicks us out of the loop. These expansions are:
meds=zeros(1,5);
for i=1:length(dat), i
meds(i)=median(dat{i});
end
disp('now the for-loop is done')
and using the while-loop it is:
meds=zeros(1,5); i=0;
while i<length(dat), i=i+1;
meds(i)=median(dat{i});
i<length(dat)
end
disp('now the while-loop is done')
From these expanded versions we see that the for-loop iterates through the values of i that are indicated by the statement immediately following the word ‘for’ (e.g., 1:10, or 4:7), and for each value of i it runs through all lines of code enclosed by the words for...end. The while loop is similar: every time it gets to the word ‘while’ it check if the logical statement next to the word ‘while’ is true. If it is, it executes the code enclosed by the words for...end, and if not it jumps to the word ‘end’ and executes any remaining code (in this case, the ‘disp’ function).