A second basic 'Find' question

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.

 Réponse acceptée

Matt Fig
Matt Fig le 15 Juin 2011

1 vote

idx = findstr([0 data>=X],[0 1]);
idx = idx(ismembc(idx,findstr(data>Y,ones(1,N))))

3 commentaires

Andrei Bobrov
Andrei Bobrov le 15 Juin 2011
Hi Matt! Your method is very good!
We have:
idx = [strfind(([0 data>X]),[0 1]);strfind(data<Y,[0 1])];
out = cell2mat(arrayfun(@(x)data(idx(1,x):idx(2,x)),1:size(idx,2),'un',0))
Andrew Newell
Andrew Newell le 16 Juin 2011
Matt - interesting use of findstr, and quite fast!
Etienne O'Brien
Etienne O'Brien le 16 Juin 2011
Thank you Matt for this answer and others for contributing.

Connectez-vous pour commenter.

Plus de réponses (2)

Andrew Newell
Andrew Newell le 14 Juin 2011

0 votes

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 commentaires

Matt Fig
Matt Fig le 15 Juin 2011
I = I.*(data>=X);
Andrew Newell
Andrew Newell le 15 Juin 2011
Thanks for noticing that!

Connectez-vous pour commenter.

Andrei Bobrov
Andrei Bobrov le 14 Juin 2011

0 votes

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 commentaires

Andrew Newell
Andrew Newell le 15 Juin 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 le 15 Juin 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;

Connectez-vous pour commenter.

Catégories

En savoir plus sur MATLAB dans Centre d'aide et File Exchange

Tags

Community Treasure Hunt

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

Start Hunting!

Translated by