Sum Numbers Excluding Zeros

Asked by Daniel Boateng

Daniel Boateng (view profile)

on 12 Apr 2019
Latest activity Commented on by Daniel Boateng

Daniel Boateng (view profile)

on 14 Apr 2019
Accepted Answer by Jon

Jon (view profile)

I have an array like this [2 2 3 4 0 0 0 0 7 8 2 2]. Please i want to add the numbers excluding the zeros to have something like this[11 0 0 0 0 19] Please is there a way I can do it. Thanks

Jon (view profile)

on 12 Apr 2019

The following code should do what you want. There may be some way to do this more elegantly, but I think this works and should be fairly efficient. I haven't thoroughly tested it for all edge cases. If this works for you it would be good to make it into a function that just took the input vector and returned the condensed output.
% code to condense non-zero elements in a vector into single values
% for example x = [0 1 0 2 2 3 4 0 0 0 0 7 8 2 2 0 3 0] should give
% xCond = [0 1 0 11 0 0 0 0 19 0 3 0]
x = [0 1 0 2 2 3 4 0 0 0 0 7 8 2 2 0 3 0];
% pad start and end of original vector with zero to allow detection of
% transitions to at ends of vector
xPad = [0 x 0];
% find locations where we transition from zero to non-zero elements
startIdx = find(xPad(1:end-1) == 0 & xPad(2:end)~=0);
% find locations where we transition from non-zero to zero elements
% find the number of non-zero segments (each pair of start and stop idx
% defines a non-zero segment that must be condensed into a single value
numSegments = length(startIdx); % startIdx and stopIdx are same length
% find the number of zero values
numZeros = sum(x == 0);
% Each pair of start and stop idx defines a non-zero segment that must be
% condensed into a single value. The length of the condensed vector will be
% the number of non-zero segments plus the number of zero elements that are
% left as spacers
% preallocate an appropriately sized vector to hold the condensed vector
xCond = zeros(1,numSegments + numZeros);
% loop through segments computing condensed sums and forming condensed
% vector
idx = startIdx(1); % initial location in the output vector
for k = 1:numSegments
% condense current segment
xCond(idx) = sum(x(startIdx(k):stopIdx(k)));
% increment the count to the next location
if k + 1 <= numSegments % watch for end condition
idx = idx + (startIdx(k+1) - stopIdx(k));
end
end

Daniel Boateng

Daniel Boateng (view profile)

on 12 Apr 2019
Thank you very much. That is what I expected

Answer by Stephen Cobeldick

Stephen Cobeldick (view profile)

on 12 Apr 2019

Simpler solution using accumarray:
>> x = [0,0,0,1,0,2,2,3,4,0,0,0,0,7,8,2,2,0,3,0];
>> y = cumsum(x==0 | [true,x(1:end-1)==0]);
>> z = accumarray(y(:),x(:))
z =
0
0
0
1
0
11
0
0
0
0
19
0
3
0

Jon

Jon (view profile)

on 13 Apr 2019
Very neat! I knew there must be some very elegant way to do this and you certainly have shown one here. Thank you for introducing me to the accumarray function, I had never encountered that but reading the documentation I can see it can do this (what you have) and much more, especially with the optional function argument.