MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn moreOpportunities for recent engineering grads.

Apply Today
Asked by Harish Chandra on 30 Apr 2013

Hello,

I want to get the conditional sum of part of a vector based on a second vector.

For example:

A = [143 14 -4 299 -29 83 151 190 178 -61 -109 ]

and

B = [1 1 -1 1 -1 1 1 1 1 -1 -1 ]

then I want to get the output:

C=[0 157 -4 299 -29 0 0 0 602 -170 ]

and

D=[0 2 1 1 1 0 0 0 4 0 2 ]

The idea is, when successive B's = 1, I add the corresponding values from A and store in C. Similarly if successive B's = -1, I add the values up and store in C. If more than 1 value in A is added, I fill the gaps in C with 0's. It would also be great if I could get a seperate array D mentioning how many values in A have been added to produce the value in C!

Please help! Thanks a lot!

*No products are associated with this question.*

Answer by Teja Muppirala on 30 Apr 2013

Accepted answer

Just for comparison, here is a FOR loop solution. FOR loops can actually be very fast, even for large arrays, especially when you are doing simple operations like this.

C = zeros(size(A)); D = zeros(size(A));

previous = B(1); runningSum = A(1); numValues = 1; for n = 2:numel(B) if B(n) == previous runningSum = runningSum + A(n); numValues = numValues+1; else C(n-1) = runningSum; D(n-1) = numValues; runningSum = A(n); numValues = 1; previous = B(n); end end C(end) = runningSum; D(end) = numValues;

Answer by Cedric Wannaz on 30 Apr 2013

Edited by Cedric Wannaz on 30 Apr 2013

The following is an example of "vector approach":

dif = [true, diff(B)~=0] ; blockId = cumsum(dif) ; blockStart = find(dif) ; blockEnd = [blockStart(2:end)-1, numel(A)] ;

blockSum = accumarray(blockId(:), A(:)) ; C = zeros(size(A)) ; C(blockEnd) = blockSum ;

blockSize = accumarray(blockId(:), ones(size(A))) ; D = zeros(size(A)) ; D(blockEnd) = blockSize ;

Running this produces:

>> C C = 0 157 -4 299 -29 0 0 0 602 0 -170

>> D D = 0 2 1 1 1 0 0 0 4 0 2

As you can see, a simpler FOR loop is likely to be more efficient for small array sizes, but this vector approach certainly wins if `A` and `B` are large.

**I don't have time to check it extensively though, and I leave that to you. Check well boundary cases in particular.**

Note that you can probably simplify the first part by computing directly `blockEnd` without defining `blockStart`, but I leave it this way for sake of clarity (or more honestly by lack of time ;-)).

## 1 Comment

Direct link to this comment:http://www.mathworks.com/matlabcentral/answers/74089#comment_146362

How large are these vectors? There is a vector way to do it (requires quite a few operations) and a way based on a simple FOR loop. The vector way is likely to be very efficiency on large vectors/arrays, and the FOR loop is likely to be more efficient on small vectors/arrays.