break the for loops in matlab - matlab

I have written a matlab code and want to terminate the code after finding the first one in the matrix. BUT, it continues until the last one and then break works. What is the problem?
% The code is as follows:
for i=1:n
for j=1:m
if (bw(i,j)==1) % element with value one
p1(1)=i;p1(2)=j;
% fprintf('value of a: %d\n', i ,j)
sprintf('Found first one in the loop!!')
break; % terminate
end
end
end

It looks like you want to find the first 1 value in a matrix, searching in row-major order (increase column index first, then row index). You can do that without loops using the find function:
M = [0 1; 1 1]; %// example matrix
v = 1; %// value you want to find
[col, row] = find(M.'==v, 1);
Note that the matrix is transposed and the order of the two outputs of find is reversed. This is because Matlab finds elements in column-major order (increase row index first, then column index).
In the above example, with
M =
0 1
1 1
the result is
row =
1
col =
2

Since break exits only the inner loop (the one that runs with j) but not the outer loop (the one that runs with i), you can tackle the problem by using a simple boolean which you initially set as false.
When you break the inner loop, change it to true and then check (in the outer loop) if such boolean is true. If it is, also break the outer loop.
IWantToBreak=false;
for i=1:n
for j=1:m
if (bw(i,j)==1) % element with value one
p1(1)=i;p1(2)=j;
% fprintf('value of a: %d\n', i ,j)
sprintf('Found first one in the loop!!')
IWantToBreak=true;
break; % terminate
end
end
if IWantToBreak==true
break;
end
end

Related

delete elements from a matrix and calculate mean

I have an N-by-M-Matrix as input called GR wich consists of the following numbers: -3,0,2,4,7,10,12
And I have to return a vector. If M=1, then it should just return the input.
If M>1 It should remove the lowest number from the matrix and then calculate the mean of the remaining numbers.
However, if one of the numbers in the row is -3, it should return the value -3 in the output.
My thoughts of the problem:
Is it possible to make a for loop?
for i=1:length(GR(:,1))
If length(GR(1,:))==1
GR=GR
end
If length(GR(1,:))>1
x=min(GR(i,:))=[] % for removing the lowest number in the row
GR=sum(x)/length(x(i,:))
I just don't have any Idea of how to detect if any of the numbers in the row is -3 and then return that value instead of calculating the mean and when I tried to delete the lowest number in the matrix using x=min(GR(i,:)) matlab gave me this error massage 'Deletion requires an existing variable.'
I put in a break function. As soon as it detects a -3 value it breaks from the loop. Same goes for the other function.
Note that it is an i,j (M*N) matrix. So you might need to change your loop.
for i=1:length(GR(:,1))
if GR(i,1)==-3
GR=-3
break
end
If length(GR(1,:))==1
GR=GR
break
end
If length(GR(1,:))>1
x=min(GR(i,:))=[] % for removing the lowest number in the row
GR=sum(x)/length(x(i,:))
end
end
you can use Nan's, nanmean, any, and dim argument in these functions:
% generate random matrix
M = randi(3);
N = randi(3);
nums = [-3,0,2,4,7,10,12];
GR = reshape(randsample(nums,N*M,true),[N M]);
% computation:
% find if GR has only one column
if size(GR,2) == 1
res = GR;
else
% find indexes of rows with -3 in them
idxs3 = any(GR == -3,2);
% the (column) index of the min. value in each row
[~,minCol] = min(GR,[],2);
% convert [row,col] index pair into linear index
minInd = sub2ind(size(GR),1:size(GR,1),minCol');
% set minimum value in each row to nan - to ignore it on averaging
GR(minInd) = nan;
% averaging each rows (except for the Nans)
res = nanmean(GR,2);
% set each row with (-3) in it to (-3)
res(idxs3) = -3;
end
disp(res)

arrange resulting loop row values into one array in matlab

Considering the fact that i have gotten some clarity on this current question, I have edited the code to conform with my current problem with the code. So now the problem i have with my code is that it does not loop any more. if i place a for loop and some conditions, the value of groups which is supposed to change with every loop does not therefore causing an error at k is 2 in the loop. The initial value of groups is gotten from the first part of the code which gets its value form a different array, but the for loop part of the code is supposed to use that initial groupsvalue and then continue changing from there. that is where the problem comes, as the value of groups refuses to change.
A = connections;
% Engine
tic
[m, n] = size(A);
groups = [];
ng = 0;
k=1;
w= 1:2:3;
u = unique(A(k,w)); % representation of kth row
[in, J] = ismember(A(k:end,:),u);
l = m-k+1;
r = repmat((1:l).', n, 1);
c = accumarray([r(in) J(in)],1,[l n]); % count
c = bsxfun(#min,c,c(1,:)); % clip
rows = sum(c,2)==2; % check if 2 elements are common
if any(rows)
ng = +1;
groups = (k-1) + [1; find(rows)];
end
gr=groups(end);
nwrry= [A(k,:);A(gr,:)];
for k=1:5
h=[];
h(k)= groups(end);
dff= setdiff(nwrry(end,:),nwrry(end-1,:));
[rw,cl]= find(nwrry==dff);
if cl==3
w=1:2:cl;
else
if cl==2
w=1:cl;
else
w=cl:2;
end
end
u = unique(A(h(k),w)); % representation of kth row
[in, J] = ismember(A(k:end,:),u);
l = m-k+1;
r = repmat((1:l).', n, 1);
c = accumarray([r(in) J(in)],1,[l n]); % count
c = bsxfun(#min,c,c(1,:)); % clip
rows = sum(c,2)==2; % check if 2 elements are common
if any(rows)
ng = ng+1;
groups = (k-1) + [1; find(rows)];
end
nwrry = [nwrry;A(groups(end),:)]
k=k+1
end
connections is the 800 by 3 array. if you want to test it and see what it gives as a result please make sure the array has at most 2 values in a row common with another row.
I have been able to answer this question. Thank you all who have commented with your advices and help because i did look into what you all said and been able to come up with something worthwhile.
The complete code is below;
%% call connections
A= connections;
[m, n] = size(A);%% calculate number of rows (m) and columns(n) in A
%% find rows with similar values as row 1
[a, b]=find(A(1:end,:) == A(1,1));%% Find rows with similar value as the first value of row 1
[a1, b1]=find(A(1:end,:) == A(1,2));%% Find rows with similar value as the second value of row 1
[a2, b2]=find(A(1:end,:) == A(1,3));%% Find rows with similar value as the third value of row 1
%% find the rows with atleast 2 values similar to row 1
int1= intersect(a,a1);%% Find same row numbers between a and a1
int2= intersect(a,a2);%% Find same row numbers between a and a2
int3= intersect(a1,a2);%% Find same row numbers between a1 and a2
ints=[int1;int2;int3];%% Place all intersections in one array(ints)
%% delete row number that is same with row number 1
ints= unique(ints);%% delete repeated row numbers
[Lia,Locb] = ismember(ints(1:end,:),1);%% Find same row numbers same with row number 1
[z, x]=find(Lia(1:end,:) == 1);%% Find row numbers equal to 1 in Lia
ints(z(1:end),:)=[];%% delete row numbers that is same with row number 1
%% place the searched row number and the similar row number in an array(gr)
gr=1;%% Place initial row number(1) in one array(gr)
tg=[a;a1;a2];%% Place all row numbers with similar value as row 1 in one array(tg)
if isempty(ints)%% conditions when ints is empty
f= setdiff(tg,gr);%% Find row numbers in tg not present in gr
gr=[gr;f(1,:)];%% add the similar row number in array gr
else %% conditions when ints is NOT empty
gr=[gr;ints(end)]; %% add the similar row number in array gr
end
%% place the searched row and the similar row in an array(nwrry)
nwrry= [A(1,:);A(gr(end),:)];
%% Create loop for all rows in A and repeat all processes above
for i=1:m-2
hrry=[];
hrry(i)= gr(end);
[a, b]=find(A(1:end,:) == A(hrry(end),1));
[a1, b1]=find(A(1:end,:) == A(hrry(end),2));
[a2, b2]=find(A(1:end,:) == A(hrry(end),3));
int1= intersect(a,a1);
int2= intersect(a,a2);
int3= intersect(a1,a2);
ints=[int1;int2;int3];
ints= unique(ints);
[Lia,Locb] = ismember(ints(1:end,:),gr(1:end,:));
[z, x]=find(Lia(1:end,:) == 1);
ints(z(1:end),:)=[];
tg=[a;a1;a2];
if isempty(ints)
f= setdiff(tg,gr);
if isempty(f)
Anb=1:m;
Anbc=Anb';
nwf= setdiff(Anbc,gr);
gr=[gr;nwf(1,:)];
else
gr=[gr;f(1,:)];
end
else
gr=[gr;ints(end)];
end
nwrry= [nwrry;A(gr(end),:)];
end

Matrix as input and output of Matlab function

For example I want to have a function which let me delete rows of my matrix where the highest value is 1. Thus I wrote:
% A is an input matrix
% pict2 suppose to be output cleared matrix
function pict2 = clear_(A)
B=A
n = size(A,1)
for i=1:n
if(max(B(i,:))==1)
B(i,:)=[]
end
end
But after I call:
pict2=clear_(pict) the Matlab resposes:
"warning: clear_: some elements in list of return values are undefined
warning: called from
clear_ at line 5 column 1 pict2 = "
I'm not sure which elements were left undefined?
The variable name of your output argument must match the variable that you want to be returned. So you'll want to change the first line to the following so that your modifications to B are saved and returned.
function B = clear_(A)
As far as your algorithm is concerned, it's not going to work because you are modifying B while trying to loop through it. Instead, you can replace your entire function with the following expression which computes the maximum value of each row, then determines if this value is equal to 1 and removes the rows where this is the case.
B(max(B, [], 2) == 1, :) == [];
I believe that, alternatively to the suggestions you already recieved, you might want to try the following. Using logicals is probably one of the best options for such a problem, since you don't need to use for-loops:
function out = clear_matr(A)
% ind is true for all the rows of A, where the highest value is not equal to 1
ind = ~(max(A, [], 2) == 1);
% filter A accordingly
out = A(ind, :);
end

quickselect code in matlab

Let us consider following pseudo code
QuickSelect(A, k)
let r be chosen uniformly at random in the range 1 to length(A)
let pivot = A[r]
let A1, A2 be new arrays
# split into a pile A1 of small elements and A2 of big elements
for i = 1 to n
if A[i] < pivot then
append A[i] to A1
else if A[i] > pivot then
append A[i] to A2
else
# do nothing
end for
if k <= length(A1):
# it's in the pile of small elements
return QuickSelect(A1, k)
else if k > length(A) - length(A2)
# it's in the pile of big elements
return QuickSelect(A2, k - (length(A) - length(A2))
else
# it's equal to the pivot
return pivot
I have wrote following code in matlab
function []=Quickselect(A,k);
% A-unsorted array
%k-we want to return kth largest element
% let r be chosen uniformly at random in the range 1 to length(A)
i=1; %initialize index
j=1; %initialize index
n=length(A);%length of array
r=floor(1+(n-1)*rand);%random index
pivot=A(r); % choose pivot as A(r);
A1=zeros(1,n); %create additional arrays
A2=zeros(1,n);%create additional arrays
for m=1:n
if A(m)<k
A1(i)=A(m);
i=i+1;
else if A(m)>k
A2(j)=A(m);
j=j+1;
end
end
end
if k <= numel(A1)
return Quickselect(A1,k);
else if k > (length(A) - length(A2))
return Quickselect(A2, k - (length(A) - length(A2)));
else
return pivot;
end
end
end
>> A=[2 1 4 3 6 5 7 9 8 10 11 13 21 12];
>> Quickselect(A,3)
Error: File: Quickselect.m Line: 23 Column: 10
Unexpected MATLAB expression.
I dont understand reason of error, can't i use recursive property in Matlab? thanks in advance
It is not a recursivity problem, it is just wrong Matlab syntax.
In Matlab, return does not force the return of a variable, but just makes the function stop and get out. If you want to return something your function should begin with:
function [outvar]=Quickselect(A,k);
And every time you have a
return pivot;
or
return Quickselect(A1,k);
You should modify it by
outvar=pivot; % or outvar=Quickselect(A1,k);
return;
Okay, here's what's wrong with your code. I've already commented about replacing pivot with k, but after looking at the code more closely I found a few more errors. #AnderBiguri already identified a couple of problems, and I'll mention those here as well for completeness.
function []=Quickselect(A,k);
As Ander mentioned, you need the return value. I'm going to directly use pivot. And function declarations don't need a ; after them. You're effectively creating a blank first line.
function pivot = Quickselect(A,k)
You had me confused for a second with the comments:
% A-unsorted array
%k-we want to return kth largest element
% let r be chosen uniformly at random in the range 1 to length(A)
The pseudocode you gave actually finds the kth smallest element. In the list [1, 2, 3, 4, 5], 1 would be the smallest element, 2 would be the second-smallest element, and 5 would be the fifth smallest-element.
i=1; %initialize index
j=1; %initialize index
n=length(A);%length of array
r=floor(1+(n-1)*rand);%random index
I don't know why you're not using randi here. Not actually wrong the way you're doing it, but it's much clearer, much more concise with randi.
r=randi(n); % random index
Note the % create additional arrays portion here:
pivot=A(r); % choose pivot as A(r);
A1=zeros(1,n); % create additional arrays
A2=zeros(1,n); % create additional arrays
These arrays are created with the same size as A and will always have the same size as A. This was addressed by Ander in his comment and will become very important later.
Now the for loop:
for m=1:n
if A(m)<k
Your pseudocode says:
if A[i] < pivot then
pivot is the value of the element chosen as the pivot and you're trying to split A into two lists: one with elements less than the pivot, and another with elements greater than the pivot. k is the index of an element whose value you're looking for. The pseudocode correctly uses pivot, so your code should be:
if A(m)<pivot
The same thing goes for A(m)>k. It should be A(m)>pivot. Also, in Matlab, the keyword is elseif, with no space. I'm deviating a bit from my method of commenting on individual lines as they occur, but I wanted to leave the next section uninterrupted to point out something else.
A1(i)=A(m);
i=i+1;
else if A(m)>k
A2(j)=A(m);
j=j+1;
end
end
end
See that first end? What does it end? It's better if you look at your whole code, but that last end ends the for loop. The second-to-last end ends the if-elsif. The first end is wrong and should be removed. Actually, and I'm very surprised Ander didn't mention this, but if you had properly indented your code you would never have created this bug. In fact, your entire code should be re-indented consistently for this reason as well as readability. The for loop section should look like this:
for m=1:n
if A(m)<pivot
A1(i)=A(m);
i=i+1;
elseif A(m)>pivot
A2(j)=A(m);
j=j+1;
end
end
Now it's quite obvious what blocks the ends go with and how many we need.
The next line in your code is:
if k <= numel(A1)
This is the bug I referred to above that's mentioned in Ander's comment. numel(A1) will always be equal to numel(A), because that's the way you created the array. Therefore, k will always be less than or equal to the size of the input array. (Well, it should be, but there's no explicit check for that in the pseudocode or your code, but oh well.)
So where do we get the number of elements actually added to A1? Well, we go back to that for loop where we were using i as the index of the next element to be added to A1 and j as the index of the next element to be added to A2. This means that the valid length of A1 is i-1 and the valid length of A2 is j-1. So your if statement should be:
if k <= (i-1)
Next we have:
return Quickselect(A1,k);
Ander Biguri also mentioned this one. Matlab does not return values this way; you simply set the value of the return variable that was defined in the function declaration. I used pivot, so we take the value returned from our recursive call to Quickselect and assign it to our copy of pivot. When the function ends, the value of this variable automatically becomes the return value.
Now for the parameters you're passing to the recursive call. I've already said that numel(A1) == numel(A). So if you recursively call Quickselect on A1, you're not actually reducing the size of the array. We only want to pass the valid portion of A1 and since we know that it has i-1 valid elements, we can just take the first i-1 elements, i.e. A1(1:i-1).
The correct line is:
pivot = Quickselect(A1(1:i-1),k);
Now we run into the length problem again, and you've switched from using numel to using length. Not actually wrong, as far as it goes, but bad style.
else if k > (length(A) - length(A2))
return Quickselect(A2, k - (length(A) - length(A2)));
This is always zero. The length of A minus the length of something that is the same length as A is zero. The valid length of A2 is j-1. Also, we already know the size of A, it's n from way up there at the beginning. The corrected lines:
elseif k > (n - (j-1))
pivot = Quickselect(A2(1:j-1), k - (n - (j-1)));
And so we come to the end of our code:
else
return pivot;
end
end
end
As mentioned, return doesn't set any return value, it just returns from the function. Since we're at the end of the function anyway, there's no need to return. Once again, proper indentation would show you that there is an extra end here as well. We need one for the if-elseif block, and one to end the function itself, but the third one is extraneous.
If you make these changes you will have a working quickselect function.

expand matrix in matlab?

I would like to expand matrix row by row under a conditional statement without initializing the matrix. In C++, simply I use std::vector and push_back method without initializing the size of the vector in C++. However, I want to do same scenario in Matlab. This is my pseudo code
for i = 1:lengt(data)
if ( condition )
K = [data(1) data(2) i]
end
K
Let us assume some working code to resemble your pseudo-code.
%// Original code
for i = 1:10
if rand(1)>0.5
data1 = rand(2,1)
K = [data1(1) data1(2) i]
end
end
Changes for "pushing data without initialization/pre-allocation":
To save data at each iteration we keeping on "stacking" data along a chosen dimension. This could be thought of as pushing data. For a 2D case, use either a "row vector push" or a "column vector push". For this case we are assuming a former case.
We don't index into K using the original iterator, but use a custom one,
that only increments when the condition is satisfied.
The code below must make it clear.
%// Modified code
count = 1; %// Custom iterator; initialize it for the iteration when condition would be satisfied for the first time
for i = 1:10
if rand(1)>0.5
data1 = rand(2,1)
K(count,:) = [data1(1) data1(2) i] %// Row indexing to save data at each iteration
count = count +1; %// We need to manually increment our custom iterator
end
end
If we assume from the above that data is an Nx2 matrix, and that you only want to save the rows that satisfy some condition, then you almost have the correct code to update your K matrix without having to initialize it to some size:
K = []; % initialize to an empty matrix
for i=1:size(data,1) % iterate over the rows of data
if (condition)
% condition is satisfied so update K
K = [K ; data(i,:) i];
end
end
K % contains all rows of data and the row number (i) that satisfied condition
Note that to get all elements from a row, we use the colon to say get all column elements from row i.