## Vectorized method to sum missed one values

### Robert Vullings (view profile)

on 19 Sep 2018
Latest activity Commented on by Robert Vullings

on 2 Nov 2018

### Amir Xz (view profile)

Hi there,
I am trying to achieve something, but I can't think of a vectorized way of doing this. The problem is as follows.
Say I have a vector of 0's and 1's, e.g. [0, 1, 1, 0, 0, 1, 0, 1]. Then I want to manipulate it in such a way that I get the following vector: [0, 2, 1, 0, 0, 3, 0, 2]. Hence, from left to right, every time a 1 occurs, it adds the number of consecutive preceding zero's, if any.
This can easily be done in a loop, but because of the vast number of computations, I am looking for a vectorized way to achieve this.
Any help is appreciated!
Best, Robert

### Amir Xz (view profile)

on 19 Sep 2018
Edited by Amir Xz

### Amir Xz (view profile)

on 19 Sep 2018

A=[0, 1, 1, 0, 0, 1, 0, 1];
[~,NonZr] = find(A~=0);
A(NonZr) = [NonZr(1),NonZr(2:end)-NonZr(1:end-1)];
Result:
A =
0 2 1 0 0 3 0 2

Show 1 older comment
Amir Xz

### Amir Xz (view profile)

on 20 Sep 2018
Thank you Guillaume, then more simple way to find indices of nonzero elements is:
NonZr = find(A);
Robert Vullings

### Robert Vullings (view profile)

on 20 Sep 2018
Thank you very much, this is indeed a very smart way to do it!
Robert Vullings

### Robert Vullings (view profile)

on 2 Nov 2018
Any ideas on how to expand this (or another method) to a 2D array?
For example, say
A=[0, 1, 1, 0, 0, 1, 0, 1;
1, 0, 1, 0, 1, 1, 0, 1];
would then become
A=[0, 2, 1, 0, 0, 3, 0, 2;
1, 0, 2, 0, 2, 1, 0, 2];

### Guillaume (view profile)

on 19 Sep 2018
Edited by Guillaume

### Guillaume (view profile)

on 19 Sep 2018

You can replace the earlier part of this answer by the compiled version of rcumsumc for speed
v = [0, 1, 1, 0, 0, 1, 0, 1];
rcum = double(~v);
csum = cumsum(rcum);
rcum(v == 1) = -diff([0, csum(v == 1)]);
rcsum = cumsum(rcum) + 1;
%all the above can be replaced by rcumsum
%rcsum = rcumsum(~v) + 1;
reploc = diff(v) == 1
v([false, reploc]) = rcsum([reploc, false])
Note that I'm not convinced that it will be faster than a well written loop (which can do the job in only one pass over the data).

#### 1 Comment

Christopher Wallace

### Christopher Wallace (view profile)

on 19 Sep 2018
This is about 20x faster than my answer when run on my machine. Nice work!

### Christopher Wallace (view profile)

on 19 Sep 2018

startingData = [0, 1, 1, 0, 0, 1, 0, 1];
stringArr = sprintf('%d', startingData ); % Convert to string for use with regexp
zerosLoc = regexp(stringArr , '(0*)'); % Find starting index of groups of 0's
onesLoc = regexp(stringArr , '(1*)'); % Find starting index of groups of 1's
startingData(onesLoc) = (onesLoc - zerosLoc) + 1; The difference in the starting location of the ones and the starting location of the zeros which will result in the number of zeros leading up to the 1.

Guillaume

### Guillaume (view profile)

on 19 Sep 2018
Conversions from numbers to strings are never fast, but
stringArr = char(startingData + '0');
will be a lot faster than using sprintf.
However, you don't need regexp and strings to find the start of the sequences.
zerosLoc = find(diff([1, startingData]) == -1); %find [1 0] transitions
onesLoc = find(diff([0, startingData]) == 1); %find [0 1] transitions
With this it may actually be faster than my solution.