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

 Respuesta aceptada

Jon
Jon el 12 de Abr. de 2019

2 votos

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 comentario

Daniel Boateng
Daniel Boateng el 12 de Abr. de 2019
Thank you very much. That is what I expected

Iniciar sesión para comentar.

Más respuestas (1)

Stephen23
Stephen23 el 12 de Abr. de 2019

1 voto

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 comentarios

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

Iniciar sesión para comentar.

Etiquetas

Preguntada:

el 12 de Abr. de 2019

Comentada:

el 14 de Abr. de 2019

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by