11

I have a matrix:

x = [0 0 0 1 1 0 5 0 7 0];

I need to remove all of the zeroes, like so:

x = [1 1 5 7];

The matrices I am using are large (1x15000) and I need to do this multiple times (5000+), so efficiency is key!

gnovice
  • 125,304
  • 15
  • 256
  • 359

6 Answers6

16

One way:

x(x == 0) = [];

A note on timing:

As mentioned by woodchips, this method seems slow compared to the one used by KitsuneYMG. This has also been noted by Loren in one of her MathWorks blog posts. Since you mentioned having to do this thousands of times, you may notice a difference, in which case I would try x = x(x~=0); first.

WARNING: Beware if you are using non-integer numbers. If, for example, you have a very small number that you would like to consider close enough to zero so that it will be removed, the above code won't remove it. Only exact zeroes are removed. The following will help you also remove numbers "close enough" to zero:

tolerance = 0.0001;  % Choose a threshold for "close enough to zero"
x(abs(x) <= tolerance) = [];
Community
  • 1
  • 1
gnovice
  • 125,304
  • 15
  • 256
  • 359
  • This fails on negative numbers Try `abs(x)<= tolerance` – KitsuneYMG Apr 10 '09 at 18:38
  • The x <= tolerance would exclude negative floating point numbers. You would probably need to expand the comparison to be x >= tolerance and x <= tolerance. The operator for logical and in matlab escapes me at this moment. – Bill Perkins Apr 10 '09 at 18:39
  • I corrected the answer to remove any value close enough to zero from either the negative or positive direction. – gnovice Apr 10 '09 at 18:40
11

Just to be different:

x=x(x~=0);

or

x=x(abs(x)>threshold);

This has the bonus of working on complex numbers too

KitsuneYMG
  • 12,753
  • 4
  • 37
  • 58
11

Those are the three common solutions. It helps to see the difference.

x = round(rand(1,15000));

y = x;

tic,y(y==0) = [];toc

Elapsed time is 0.004398 seconds.

y = x;

tic,y = y(y~=0);toc

Elapsed time is 0.001759 seconds.

y = x;

tic,y = y(find(y));toc

Elapsed time is 0.003579 seconds.

As you should see, the cheapest way is the direct logical index, selecting out the elements to be retained. The find is more expensive, since matlab finds those elements, returning a list of them, and then indexes into the vector.

Jonas
  • 74,690
  • 10
  • 137
  • 177
  • Wow! Are those numbers right? I could have sworn that "y(y==0)=[];" and "y=y(y~=0);" were comparable to each other speed-wise. I'll have to check my numbers again. – gnovice Apr 10 '09 at 22:02
  • Never mind... I just found a blog post by Loren at the mathworks that addresses exactly this problem, and it seems to agree with your numbers. – gnovice Apr 10 '09 at 22:08
  • @gnovice Note that you can now use `[~, ~, y] = find(y)` which should give similar performance to the solution with logical indexing. – Dennis Jaheruddin Jul 23 '13 at 11:48
3

Here's another way

y = x(find(x))

I'll leave it to you to figure out the relative efficiency of the various approaches you try -- do write and let us all know.

High Performance Mark
  • 77,191
  • 7
  • 105
  • 161
2

Though my timing results are not conclusive to whether it is significantly faster, this seems to be the fastest and easiest approach:

y = nonzeros(y) 
Dennis Jaheruddin
  • 21,208
  • 8
  • 66
  • 122
0
x = [0 0 0 1 1 0 5 0 7 0]
y = [0 2 0 1 1 2 5 2 7 0]

Then x2 and y2 can be obtained as:

x2=x(~(x==0 & y==0))
y2=y(~(x==0 & y==0))

x2 = [0     1     1     0     5     0     7]
y2 = [2     1     1     2     5     2     7]

Hope this helps!

Autonomous
  • 8,935
  • 1
  • 38
  • 77