MATLAB Answers

1

Sum Numbers Excluding Zeros

Asked by Daniel Boateng on 12 Apr 2019
Latest activity Commented on by Daniel Boateng on 14 Apr 2019
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

  0 Comments

Sign in to comment.

Tags

2 Answers

Jon
Answer by Jon
on 12 Apr 2019
 Accepted Answer

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
stopIdx = find(xPad(2:end)==0 & xPad(1:end-1)~=0)-1;
% 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

  1 Comment

Thank you very much. That is what I expected

Sign in to comment.


Answer by Stephen Cobeldick 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

  3 Comments

Jon
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.
madhan ravi
on 13 Apr 2019
+1 for both the solutions, Jonathan I highly appreciate your effort too, the solution proposed by you was innovative.
this one also short and good. Thanks for your effort

Sign in to comment.