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

New to MATLAB?

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

Asked by Harish Chandra

Harish Chandra

on 30 Apr 2013
Accepted Answer by Teja Muppirala

Teja Muppirala

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

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

Harish Chandra

Products

No products are associated with this question.

2 Answers

Answer by Teja Muppirala

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

Teja Muppirala

Answer by Cedric Wannaz

Cedric Wannaz

on 30 Apr 2013
Edited by Cedric Wannaz

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

Cedric Wannaz

Contact us