A second basic 'Find' question

1 view (last 30 days)
Etienne O'Brien
Etienne O'Brien on 14 Jun 2011
I want to identify starting point of a range of values whereby the first value is greater than or equal to X and all subsequent values are greater than another value (Y), which smaller than X. The exact length of the range isn't known exactly (it has at least N points) no other data range of similar length or longer occurs within the data set.
For example: 1, 2, 3, 4, 5,6,3.5,3.1, 7,6,8,6,5,3,1,2,3,4, X=4 Y=3 N=5 I want to find the range which starts greater than or equal to 4 and doesn't fall below 3. I know that there are at least 5 data points within the range of interest.

Accepted Answer

Matt Fig
Matt Fig on 15 Jun 2011
idx = findstr([0 data>=X],[0 1]);
idx = idx(ismembc(idx,findstr(data>Y,ones(1,N))))
  3 Comments
Andrew Newell
Andrew Newell on 16 Jun 2011
Matt - interesting use of findstr, and quite fast!
Etienne O'Brien
Etienne O'Brien on 16 Jun 2011
Thank you Matt for this answer and others for contributing.

Sign in to comment.

More Answers (2)

Andrew Newell
Andrew Newell on 14 Jun 2011
My initial response was not very robust, so I have completely rewritten it:
data = data(:);
% Find how many adjacent terms are > Y
I = data>Y;
I = conv(double(I),ones(N,1));
I = I(N:end);
% Select elements > X and return length of sequence
I = I.*(data>=X);
% See if any sequences are long enough and display results
i1 = find(I>=N,1,'first');
if any(i1)
i2 = i1+I(i1)-1;
disp(['Index range = ',num2str(i1),':',num2str(i2)])
disp(['Selected data = ',num2str(data(i1:i2)')])
else
disp('No sequence found.')
end
  2 Comments
Matt Fig
Matt Fig on 15 Jun 2011
I = I.*(data>=X);
Andrew Newell
Andrew Newell on 15 Jun 2011
Thanks for noticing that!

Sign in to comment.


Andrei Bobrov
Andrei Bobrov on 14 Jun 2011
I1 = find(data == X,1);
X1 = data(I1:end) > Y;
xf = find([true diff(X1)~=0]);
idx = [xf; xf(2:end)-1 length(X1)];
idx(:,X1(idx(1,:))==0)=[];
idx1 = idx + I1 -1;
[non,I] = max(diff(idx1));
out = data(idx1(1,I):idx1(2,I));
MORE
idx = bsxfun(@plus,1:(N+1),(0:length(data)-N-1)');
ii = find(data==X,1);
id = idx(ii:end,:);
I = find(all(data(id) > Y,2));
out = data(id(I(1)):id(I(end)+N))
EDIT after comments of Andrew Newell. Very much thanks Andrew!
idx = bsxfun(@plus,1:(N+1),(0:length(data)-N-1)');
ii = find(data>=X,1);
id = idx(ii:end,:);
I = find(any(data(id) > Y,2));
out = data(id(I(1)):id(I(end)));
MORE variant (after last comments of Andrew Newell)
data = data(:);
dg3 = data > Y;
dge4 = data >= X;
xstrts = [true; diff(dge4)~=0]&dge4;
yends = flipud([true; diff(flipud(dg3))~=0])&dg3;
ii = [find(xstrts) find(yends) ];
out = cell2mat(arrayfun(@(x)data(ii(x,1):ii(x,2))',1:size(ii,1),'un',0));
  2 Comments
Andrew Newell
Andrew Newell on 15 Jun 2011
Try this test example:
data = rand(1,10000); data(101:105)=[4.1 3.3 3.3 3.3 3.3];
X=4; Y=3; N=5;
Andrew Newell
Andrew Newell on 15 Jun 2011
You're welcome! Here's another:
data = rand(1,1000); data(101:105)=[4.1 3.3 3.3 3.3 3.3]; data(1:4) = [4.1 3.3 3.3 3.3];
X=4; Y=3; N=5;

Sign in to comment.

Tags

Community Treasure Hunt

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

Start Hunting!