# Finding the number of rows to the next row containing a 1

2 views (last 30 days)

Show older comments

Hi

I have a column vector of 1s and 0s and I want to find find the number of rows to the next row containing a 1. For example:

A = [0 0 0 1 0 1 1 1 0 0 0 0 0 1]';

I would like the code to return

B = [3 2 1 0 1 0 0 0 5 4 3 2 1 0]';

Is there a vectorized way that this can be done?

Thanks in advance

##### 10 Comments

Bruno Luong
on 28 Aug 2020

Very convincing Stephen. In my laptop it's even more obvious

t Rik = 0.680010 [s]

t Bruno = 0.378046 [s]

t Stephen = 0.107799 [s]

In your for-loop code I would cast B initialization in double (in case A is logical)

B = double(A);

or

B = zeros(size(A));

Bruno Luong
on 28 Aug 2020

Edited: Bruno Luong
on 28 Aug 2020

As I'm slightly surprised by the performance of the for-loop (I would expext it's good but not THAT good), I then try to see how far it from a MEX implementation. And I'm stunned, it's almost as fast (even faster for smaller array).

t Rik = 0.651531 [s]

t Bruno = 0.379362 [s]

t Stephen = 0.104442 [s]

t MEX = 0.073168 [s]

The code (benchmark + Cmex) is in the attacheh file for those who wants to play with.

I must congratulat TMW for improving the for-loop performance over many years.

### Accepted Answer

Rik
on 27 Aug 2020

Edited: Rik
on 27 Aug 2020

It took some time, but here is a solution that should also work for large matrices.

clc,clear

format compact

A = [0 0 0 1 0 1 1 1 0 0 0 0 0 1]';

% 3 2 1 0 1 0 0 0 5 4 3 2 1 0

B=A;

pad=B(end)~=1;

if pad,B(end+1)=1;end %this method requires the last position to be a 1

B=flipud(B);

C=zeros(size(B));

C(B==1)=[0;diff(find(B))];

C=ones(size(B))-C;

out=cumsum(C)-1;

out=flipud(out);

if pad,out(end)=[];end

%only for display:

[A out]

##### 4 Comments

Rik
on 27 Aug 2020

### More Answers (3)

Binbin Qi
on 27 Aug 2020

A = [0 0 0 1 0 1 1 1 0 0 0 0 0 1]';

C = find(A);

D = (1:length(A)) - C;

D(D>0) = D(D>0) + inf';

min(abs(D))'

ans =

3

2

1

0

1

0

0

0

5

4

3

2

1

0

##### 6 Comments

Bruno Luong
on 27 Aug 2020

Edited: Bruno Luong
on 27 Aug 2020

As much as I love vectorization, this problem is a typical case where the for-loop method is easier, faster, more readable.

This code is ready for 2D array, it works along the first dimension independently.

A=rand(30000,1000)>0.7;

tic

Al=logical(A);

B=zeros(size(A));

b=B(1,:);

for k=size(B,1):-1:1

b = b+1;

b(Al(k,:))=0;

B(k,:)=b;

end

toc

Bruno Luong
on 28 Aug 2020

Edited: Bruno Luong
on 28 Aug 2020

Now I just discover CUMSUM has direction option, this is based on Rik's cumsum method, but avoid the double flipping.

B = ones(size(A));

i1 = find(A);

B(i1) = 1-diff([i1;size(A,1)+1]);

B = cumsum(B,'reverse');

##### 1 Comment

Rik
on 28 Aug 2020

### See Also

### Categories

### Community Treasure Hunt

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

Start Hunting!