[matlab] How to delete zero components in a vector in Matlab?

I have a vector for example

a = [0 1 0 3]

I want to turn a into b which equals b = [1 3].

How do I perform this in general? So I have a vector with some zero components and I want to remove the zeroes and leave just the non-zero numbers?

This question is related to matlab

The answer is


If you just wish to remove the zeros, leaving the non-zeros behind in a, then the very best solution is

a(a==0) = [];

This deletes the zero elements, using a logical indexing approach in MATLAB. When the index to a vector is a boolean vector of the same length as the vector, then MATLAB can use that boolean result to index it with. So this is equivalent to

a(find(a==0)) = [];

And, when you set some array elements to [] in MATLAB, the convention is to delete them.

If you want to put the zeros into a new result b, while leaving a unchanged, the best way is probably

b = a(a ~= 0);

Again, logical indexing is used here. You could have used the equivalent version (in terms of the result) of

b = a(find(a ~= 0));

but mlint will end up flagging the line as one where the purely logical index was more efficient, and thus more appropriate.

As always, beware EXACT tests for zero or for any number, if you would have accepted elements of a that were within some epsilonic tolerance of zero. Do those tests like this

b = a(abs(a) >= tol);

This retains only those elements of a that are at least as large as your tolerance.


Data

a=[0  3   0   0   7   10   3   0   1   0   7   7   1   7   4]

Do

aa=nonzeros(a)'

Result

aa=[3   7   10   3   1   7   7   1   7   4]

Why not just, a=a(~~a) or a(~a)=[]. It's equivalent to the other approaches but certainly less key strokes.


I often ended up doing things like this. Therefore I tried to write a simple function that 'snips' out the unwanted elements in an easy way. This turns matlab logic a bit upside down, but looks good:

b = snip(a,'0')

you can find the function file at: http://www.mathworks.co.uk/matlabcentral/fileexchange/41941-snip-m-snip-elements-out-of-vectorsmatrices

It also works with all other 'x', nan or whatever elements.


You could use sparse(a), which would return

(1,2) 1

(1,4) 3

This allows you to keep the information about where your non-zero entries used to be.


b = a(find(a~=0))

I just came across this problem and wanted to find something about the performance, but I couldn't, so I wrote a benchmarking script on my own:

% Config:
rows = 1e6;
runs = 50;

% Start:
orig = round(rand(rows, 1));

t1 = 0;
for i = 1:runs
    A = orig;
    tic
    A(A == 0) = [];
    t1 = t1 + toc;
end
t1 = t1 / runs;

t2 = 0;
for i = 1:runs
    A = orig;
    tic
    A = A(A ~= 0);
    t2 = t2 + toc;
end
t2 = t2 / runs;

t1
t2
t1 / t2

So you see, the solution using A = A(A ~= 0) is the quicker of the two :)