MATLAB Answers

Replacing Values Between a 0 and a 1 in a Vector

3 views (last 30 days)
Daniel Steyer
Daniel Steyer on 18 May 2020
Commented: Robert U on 25 May 2020
Hello,
I have a data set vector that I've reduced down to 0's, 1's, and 2's. What I want to do is replace any 2's with 0's if they are following a 0, up until the next 1 shows up. For example:
if the original vector: A = [0 0 0 2 2 2 1 2 1 2 2 0 0]
the new vector : B = [0 0 0 0 0 0 1 2 1 2 2 0 0]
My vectors will have about 25,000 to 500,000 data points. Any way that I've tried to do this ends up taking way too long. I'd be appreciative of any advice that you'd be willing to give. If it helps, 0's will never be followed directly by 1's, and any 2's following a 0 will always lead into a 1 before the next 0 shows up.
Daniel

  0 Comments

Sign in to comment.

Accepted Answer

Robert U
Robert U on 18 May 2020
Hi Daniel Steyer,
this code snippet should provide the requested functionality.
cIn = cellfun(@num2str,num2cell(A),'UniformOutput',false);
strIn = [cIn{:}];
indToChange = regexp(strIn,'(?<=0)(2)+(?=1)','tokenExtents');
for indChanges = 1:numel(indToChange)
dInput(indToChange{indChanges}(1):indToChange{indChanges}(2)) = 0;
end
B = dInput;
Kind regards,
Robert

  3 Comments

Daniel Steyer
Daniel Steyer on 21 May 2020
Hey Robert,
I think I've got it up and running, thanks for the help!
Best,
Daniel
Stephen Cobeldick
Stephen Cobeldick on 22 May 2020
Note that this
cIn = cellfun(@num2str,num2cell(A),'UniformOutput',false);
strIn = [cIn{:}];
should be replaced with this simpler and much more efficient code:
strIn = sprintf('%u',A);
Robert U
Robert U on 25 May 2020
Thanks Stephen, I did not see that. I like your suggested improvement.

Sign in to comment.

More Answers (1)

Stephen Cobeldick
Stephen Cobeldick on 18 May 2020
Edited: Stephen Cobeldick on 22 May 2020
This should be reasonably efficient:
A = [0,0,0,2,2,2,1,2,1,2,2,0,0];
D = diff(A);
B = find([0,D]==2);
E = find([D==-1,true] & A==2);
for k = 1:numel(B)
A(B(k):E(k)) = 0;
end
Giving:
A =
0 0 0 0 0 0 1 2 1 2 2 0 0
Note that this approach relies on your statement "...any 2's following a 0 will always lead into a 1..."
EDIT: more robust end detection:
A = [0,0,0,2,2,2,1,2,1,2,2,0,0,0,0,0,2,2,2,1,2,1,2,2,0,0];
D = diff(A);
B = find([false,D==2]);
E = find([D==-1,true]);
for k = 1:numel(B)
X = B(k):E(find(E>B(k),1));
A(X) = 0;
end

  3 Comments

Daniel Steyer
Daniel Steyer on 21 May 2020
Hey Stephen,
Thanks for the feedback. The approach worked well on the tester set, but I'm having trouble applying it to larger data sets where multiple regions need to be acted on. For example, if I string two A's together in a vector, it doesn't recognize the second set of 2's to be replaced. E does recognize the final 2 in each chunk to be replaced, but it also recognizes any other 2's that are followed by a 1, which I think trips up the final step. For the below example, when k=2, E(k)=8 when it should equal 19 to make this work.
A=[0,0,0,2,2,2,1,2,1,2,2,0,0]
A2=[A,A]
D=diff(A2)
B=find([0,D]==2)
%B=[4,17]
E=find([D==-1,true]&A==2)
%E=[6,8,19,21]
for k=1:numel(B)
A2(B(k):E(k))=0
end
% The final output A2=[0,0,0,0,0,0,1,2,1,2,2,0,0 , 0,0,0,2,2,2,1,2,1,2,2,0,0]
I think that this approach is close to working and just needs a more selective way of creating E values. I'll see if I can't make it work.
Stephen Cobeldick
Stephen Cobeldick on 21 May 2020
Yes you are right, detecting the end index was not very robust. I tried various methods, and this worked well:
A = [0,0,0,2,2,2,1,2,1,2,2,0,0,0,0,0,2,2,2,1,2,1,2,2,0,0];
D = diff(A);
B = find([false,D==2]);
E = find([D==-1,true]);
for k = 1:numel(B)
X = B(k):E(find(E>B(k),1));
A(X) = 0;
end
Giving:
A =
0 0 0 0 0 0 1 2 1 2 2 0 0 0 0 0 0 0 0 1 2 1 2 2 0 0
Daniel Steyer
Daniel Steyer on 22 May 2020
The new version worked like a charm! Thanks for your help.

Sign in to comment.

Products