can this be done without a for loop?

3 views (last 30 days)
Luke
Luke on 20 Jan 2012
I have a huge matrix M such that each row is ascending ordered. I find if/where each row exceeds a certain threshold by looking at the last column of cumsum(M>threshold,2).
Rows that do not exceed threshold are left unchanged. For each row that does exceed the threshold, I find the first element on that row that's larger than the threshold and set it to -1. Note that these elements will be on different columns. Then, all elements between -1 and the end of the row are set to zero. For example,
M=[1 2 3 4; 1 4 6 8; 2 6 7 9]; threshold=5;
I need
result=[1 2 3 4; 1 4 -1 0; 2 -1 0 0];
Thanks!

Accepted Answer

Alex
Alex on 20 Jan 2012
The following will put all elements above your threshold value to 0.
[row, col, index] = find( M > threshold);
M(index) = 0;
This next part will put the -1 at the first element like you want.
for i = 1:length(row)
if(i > 1)
if(row(i) < row(i-1))
%the previous row was larger than the current row, break the loop
break;
end
end
%found the first element of the row that exceeds the threshold
M(row(i),col(i)) = -1;
end
Another option, is to do a loop and look at it row by row.
[row, col] = size(M);
for i = 1:row
index = find(M(i,:) > threshold, 1);
if(exists(index))
M(i,index) = -1;
M(i,index+1:end) = zeros(1,col-index);
end
end
  1 Comment
Luke
Luke on 20 Jan 2012
I already have implemented something similar to your loop solution. But since I figured out a way of setting the -1's without a loop, I was wondering if I could do everything without a loop.

Sign in to comment.

More Answers (2)

Sean de Wolski
Sean de Wolski on 20 Jan 2012
So something like:
A = sort(magic(5),2); %determinant sample data
thresh = 22; %greater than this
idx = A>thresh; %index
rows = any(idx,2); %which rows?
A(rows,:) = -1; %set 'em to -1
A(idx) = 0; %change back the parts that weren't

Luke
Luke on 20 Jan 2012
Although Alex's answer is not complete, he sent me on the right path, so I gave him credit for the solution.
[row, col] = find( M > threshold);
M(sub2ind(size(M),row,col))=0; clear row col
index=cumsum(M > threshold,2);
index=index(:,end); % the columns where to place -1's
row=1:size(M,1);
row=row(index>0); % only rows that exceed threshold
col=size(M,2)-index(index>0)+1;
M(sub2ind(size(M),row,col))=-1;
  1 Comment
Sean de Wolski
Sean de Wolski on 20 Jan 2012
for medium to large M, sub2ind is probably slower than a for loop.

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!