Finding Consecutive True Values in a Vector

I want to sum consecutive 1 values given a logical input vector. An example of input and output is below. Notice that the output is the sum of the previous elements that were 1 and if a zero element is encountered, the sum starts over. I am trying to avoid a for loop here if I can. Suggestions?
Input Output
0 0
0 0
0 0
1 1
0 0
1 1
0 0
0 0
1 1
1 2
1 3
1 4
0 0
1 1
0 0
1 1
1 2
0 0

 Akzeptierte Antwort

Andrei Bobrov
Andrei Bobrov am 5 Feb. 2014
Bearbeitet: Andrei Bobrov am 5 Feb. 2014

3 Stimmen

a0 = a(:); % input vector
ii = strfind(a0',[1 0]);
a1 = cumsum(a0);
i1 = a1(ii);
a0(ii+1) = -[i1(1);diff(i1)];
out = cumsum(a0); % output vector

3 Kommentare

Azzi Abdelmalek
Azzi Abdelmalek am 5 Feb. 2014
Andrei, you didn't define a0, I guess a0=a(:) in the first line. Your code is slightly faster then Roger's
Andrei Bobrov
Andrei Bobrov am 5 Feb. 2014
Thank you Azzi for reply. I corrected.
Jason Nicholson
Jason Nicholson am 7 Feb. 2014
Bearbeitet: Azzi Abdelmalek am 7 Feb. 2014
I had to work this line by line to figure out what it was doing. Very nice solution. To summarize, you add values at the consecutive 1's break to make the cumulative sum correct at the right elements. Great work!
Documented Code:
a=[0 0 0 1 0 1 0 0 1 1 1 1 0]';
a0 = a;
% Find the end of any consecutive 1's in a0
ii= strfind(a0',[1 0]);
a1 = cumsum(a);
% Cumulative sum at end of any consecutive 1's in a0
i1 = a1(ii);
% Places the amount to subtract during cumulative-sum 1-element past the
% consecutive 1's in a to produce only the cumulative sum of consecutive
% 1's in a0. If this is confusing, output a0 after this step.
a0(ii+1) = -[i1(1);diff(i1)];
a0
% output vector
out = cumsum(a0);
out
Outputs this:
a0' = 0 0 0 1 -1 1 -1 0 1 1 1 1 -4
out' =0 0 0 1 0 1 0 0 1 2 3 4 0

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (3)

Roger Stafford
Roger Stafford am 5 Feb. 2014

2 Stimmen

Let the input column vector be called x.
y = [x;0];
f = find(diff([0;y])~=0);
p = f(2:2:end);
y(p) = y(p)-p+f(1:2:end-1);
y = cumsum(y(1:end-1));
Then y is your output.
Azzi Abdelmalek
Azzi Abdelmalek am 4 Feb. 2014
Bearbeitet: Azzi Abdelmalek am 4 Feb. 2014

1 Stimme

a=[0 0 0 1 0 1 0 0 1 1 1 1 0]'
ii1=strfind([0 a' 0],[0 1])
ii2=strfind([0 a' 0],[1 0])-1
out=zeros(1,numel(a));
for k=1:numel(ii1)
c1=ii1(k);
c2=ii2(k);
out(c1:c2)=1:c2-c1+1
end
out'

3 Kommentare

Jason Nicholson
Jason Nicholson am 4 Feb. 2014
Bearbeitet: Jason Nicholson am 5 Feb. 2014
Azzi,
Thanks for the answer but I am trying to totally avoid the loop if possible. I think it can be done.
Image Analyst
Image Analyst am 5 Feb. 2014
Don't be afraid of for loops. The fear of them is way overblown, especially for more recent versions of MATLAB. Unless your vector is tens of millions of elements long, I wouldn't worry about it. I would choose the one answer from the 3 that is the most well commented, intuitive, and easy to understand , if there is any. Any speed differences are probably negligible.
Jason Nicholson
Jason Nicholson am 7 Feb. 2014
Fair enough Azzi.

Melden Sie sich an, um zu kommentieren.

Jos (10584)
Jos (10584) am 7 Feb. 2014

0 Stimmen

Hide the loops ;-)
input = [1 0 1 1 0 0 1 1 1 0 1 0 1 1 1 1 0]
[~,~,C] = logicalfind(input,1) ;
C = cellfun(@cumsum, C,'un',0) ;
output = input ;
output(output==1) = [C{:}]
LOGICALFIND can be downloaded here:

Community Treasure Hunt

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

Start Hunting!

Translated by