Discover MakerZone

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

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

How to calculate conditional sum of a part of vector/array based on a 2nd one

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!

1 Comment

Cedric Wannaz on 30 Apr 2013

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.

Harish Chandra

Products

No products are associated with this question.

2 Answers

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;

0 Comments

Teja Muppirala
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 ;-)).

0 Comments

Cedric Wannaz

Contact us