Vectorized method to sum missed one values

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

 采纳的回答

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

4 个评论

This is probably the simplest solution.
There's no point in using the two outputs version of find, so:
NonZr = find(A~=0);
which then works equally well for column vectors.
Thank you Guillaume, then more simple way to find indices of nonzero elements is:
NonZr = find(A);
Thank you very much, this is indeed a very smart way to do it!
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];

请先登录,再进行评论。

更多回答(2 个)

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 个评论

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

请先登录,再进行评论。

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.

1 个评论

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.

请先登录,再进行评论。

类别

帮助中心File Exchange 中查找有关 Characters and Strings 的更多信息

Community Treasure Hunt

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

Start Hunting!

Translated by