18

I have an array:

[0, 5, 6, 0, 0, 2, 5]

I would like to remove all zeros from it, so that this returns (keeping the same order):

[5, 6, 2, 5]

Is there any easier way to remove all zeros than the following?

int[] array = {0, 5, 6, 0, 0, 2, 5};
        int len = 0;
        for (int i=0; i<array.length; i++){
            if (array[i] != 0)
                len++;
        }
        int [] newArray = new int[len];
        for (int i=0, j=0; i<array.length; i++){
            if (array[i] != 0) {
                newArray[j] = array[i];
                j++;
            }
        }

I haven't been able to find any method in the Arrays class, and Google/SO searches didn't give me any good answers.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
Hidde
  • 11,493
  • 8
  • 43
  • 68
  • 6
    The simplest solution is to avoid adding them in the first place. – Peter Lawrey Jan 08 '12 at 11:49
  • 1
    You need a new array with a new length, so you will need to do the copy anyway. Working with a collection will save you the need to find the final size up front. – Thorbjørn Ravn Andersen Jan 08 '12 at 11:53
  • My situation: the array is a board, of a game. There are many possibilities when there exist no 'items' in one or more holes. So the zeros will be there, that is why I am asking... – Hidde Jan 08 '12 at 11:54
  • Where it is possible to avoid adding zeroes, Peter's comment to avoid adding them in the first place is the best method. Where it is not possible to avoid adding zeroes, in instances such as a client's output, your algorithm is optimal. – Zéychin Jan 08 '12 at 11:54
  • I apologize in advance for the smartassed-ness of my answer, but if you were coding C# you'd do sumpin like int[] filtered = (from i in array where i != 0 select i).ToArray(); and be done with it. – echo Jan 08 '12 at 12:12
  • If the O.P. were coding in C#, I don't know that he or she would be as worried about optimizing code like this. :P. – Zéychin Jan 08 '12 at 12:14
  • 2
    This particular problem is in Java, and that's why I am asking this with the Java tag. – Hidde Jan 08 '12 at 12:23

11 Answers11

25

One loop to either count or filter out the zeros cannot be avoided; however, the second loop can be avoided with the use of System.arraycopy().

This function will make a copy of an existing array into an array of different length, which means that before we use it our array must already be free from zeros. Therefore, in the first loop we cannot just count the zeros, we have to also filter them out. Here is how to actually do it:

int targetIndex = 0;
for( int sourceIndex = 0;  sourceIndex < array.length;  sourceIndex++ )
    if( array[sourceIndex] != 0 )
        array[targetIndex++] = array[sourceIndex];
int[] newArray = new int[targetIndex];
System.arraycopy( array, 0, newArray, 0, targetIndex );
return newArray;
Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
  • 1
    But then you end with an `Integer[]` and not an `int[]` – Robin Jan 08 '12 at 11:52
  • 3
    @Robin No you don't. How is that? – Mike Nakis Jan 08 '12 at 11:53
  • Performance is not really a problem here, I was looking for shorter ways to write the above. I like ArrayLists, but hoped there would be a shorter way just using arrays. – Hidde Jan 08 '12 at 11:54
  • Hidde, I amended my answer. I think this solution is the best. – Mike Nakis Jan 08 '12 at 11:58
  • Won't you end up with [0, 5, 6, 0] in your example? – Hidde Jan 08 '12 at 11:59
  • @MikeNakis since you cannot have a `List`. So you would have to manually convert the resulting `Integer[]` (which you get from `List#toArray`) to an `int[]` – Robin Jan 08 '12 at 12:02
  • I'm sorry, I have read it wrongly. I didn't see the value of array[i] was put into array[j]. – Hidde Jan 08 '12 at 12:04
  • 2
    @Robin I took a look at the documentation, and it appears that you are right. It has been a long time since I last wrote a line of code in Java, and I have been using C# since then, in which it is possible to have an array-list of primitive `int`s. I will correct my answer, thank you. – Mike Nakis Jan 08 '12 at 12:12
  • It is true a Integer[] will result from an list.toArray(), however you can harmlessly cast an Integer to int (in Java), to there is no problem there. – Hidde Jan 08 '12 at 12:20
  • Yes, but then you will need another `int` array allocation, and another loop in order to perform these casts, because toArray() will give you an array of `Integer`s, not an array of `int`s. – Mike Nakis Jan 08 '12 at 12:21
13

How about this:

Integer[] numbers = {1, 3, 6, 0, 4, 0, 3};
List<Integer> list = new ArrayList<Integer>(Arrays.asList(numbers));
list.removeAll(Arrays.asList(Integer.valueOf(0)));
numbers = list.toArray(new Integer[list.size()]);
System.out.println(Arrays.toString(numbers));

OUTPUT:

[1, 3, 6, 4, 3]
Eng.Fouad
  • 115,165
  • 71
  • 313
  • 417
  • 1
    I understood most of this answer, except in the line `numbers = list.toArray(new Integer[0]);`, what does `new Integer[0]` help in? I understand that it initializes a new Integer array with size 0, but how does it help? – Manish Giri Mar 31 '15 at 04:37
  • 2
    @ManishGiri sorry to reply to a comment from six years ago, you probably already figured it out. Perhaps it will be useful to someone else. Creating a zero-sized array allows the toArray() method to find the type of the returned array using the reflection. You have to do this in order to explicitly determine the type of the returned array at compile time. By the way such array creation is pretty well optimized in the latest versions of JVM and works fast. – Nikita Kobtsev Oct 30 '21 at 20:39
5

With Java 8 you can make a stream out of the array, apply .filter() and then convert it back into an array :

int[] array = {0, 5, 6, 0, 0, 2, 5};

int[] filteredArray = Arrays.stream(array).filter(num -> num != 0).toArray();    

// filteredArray = {5, 6, 2, 5};
Akis
  • 89
  • 1
  • 4
4

You can achieve this with one loop only. Whether this is better or more clear is a matter of personal taste I am afraid.

int[] array = {0, 5, 6, 0, 0, 2, 5};
int[] temp = new int[array.length];
int numberOfZeros = 0;
for (int i=0; i<array.length; i++){
  if (array[i] != 0){
    temp[i-numberOfZeros] = array[i];
  } else {
    numberOfZeros++;
  }
}
int[] result = new int[temp.length-numberOfZeros];
System.arraycopy(temp, 0, result, 0, result.length);

Another option would be to use a List implementation like ArrayList from which you can just remove elements, but then you will have to work with Integer instances and not with ints

List<Integer> originalList = ....;
Iterator<Integer> iterator = originalList.iterator();
while ( iterator.hasNext() ) {
  Integer next = iterator.next();
  if ( next == 0 ){
    iterator.remove();
  }
}
//convert to array if needed
Integer[] result = originalList.toArray( new Integer[originalList.size()]);
Jeen Broekstra
  • 21,642
  • 4
  • 51
  • 73
Robin
  • 36,233
  • 5
  • 47
  • 99
3

This example uses Apache Commons library , I hope this will be useful to you

import org.apache.commons.lang.ArrayUtils;

public class Test {
    public static void main(String args[]) {
        int[] array = {0, 5, 6, 0, 0, 2, 5};

        // this loop is to remove all zeros
        while(ArrayUtils.contains(array, 0))
            array = ArrayUtils.removeElement(array, 0);

        // this loop will print the array elemnents
        for(int i : array)
            System.out.println(i);

    }
}
  • 1
    Apache commons lang 3.5 now contains removeAllOccurences(T[] array, T element) which does exactly what the OP wants and what you suggested, but without having to loop. – GriffinG Jun 07 '17 at 01:29
2

Does the programming language you use employ .map or .reduce functions, or is there an extension that allows you to do this?

In Swift, you can do this via .filter; observe

var orders = [0, 5, 6, 0, 0, 2, 5]

orders = orders.filter({ $0 != 0 })

print (orders)

This returns [5, 6, 2, 5], retaining your order

zardon
  • 1,601
  • 4
  • 23
  • 46
2

You can remove zeros in O(1) extra space. Instead of copying the elements into another array you can just return the size and print the same array:

public class RemoveZeros {
    
    static int removeZeros(int[] a){
        int j =0;
        
        for(int i =0;i<a.length;i++) {
            if(a[i] !=0) {
                a[j] = a[i];
                j++;
            }
            
        }
        
        return j;
    }
    public static void main(String[] args) {
        int[] a = new int[]{0, 5, 6, 0, 0, 2, 5};
        int val = removeZeros(a);
        for(int i =0;i<val;i++)
            System.out.println(a[i]);
    }
}
charleslparker
  • 1,904
  • 1
  • 21
  • 31
1

Try the basic way:

public int[] convert(int[] data) {
    int count =0;
    for (int i =0; i< data.length; i++) {
        if(data[i]==0)
            count++;
    }
    int[] nonZero = new int[data.length-count];
    int j =0;
    for(int i = 0; i<data.length; i++) {
        if(data[i]!=0) {
            nonZero[j] = data[i];
            j++;
        }
    }
    return nonZero;
}
xKobalt
  • 1,498
  • 2
  • 13
  • 19
1

You can use a Vector:

Vector vec = new Vector();
for (int i=0; i<array.length; i++){
   if (array[i] != 0)
      vec.add(array[i]);
}
vec.toArray()

(this isn't the precise syntax, but you get the idea..)

Guy
  • 14,178
  • 27
  • 67
  • 88
  • I prefer using an ArrayList, since it uses generics. – Martijn Courteaux Jan 08 '12 at 11:55
  • @MartijnCourteaux `Vector` can make use of generics as well. There are far better reasons to opt for an `ArrayList` instead of a `Vector` (see for example [this question on SO](http://stackoverflow.com/questions/2986296/what-are-the-differences-between-arraylist-and-vector)) – Robin Jan 08 '12 at 12:08
1

If you are allowed to user List instead of array, you can do actually nothing but create a new Iteratable interface and apply a method to it like google-collections Collections2.filter() does, you can check it out.

George
  • 4,029
  • 2
  • 22
  • 26
0
public class RemoveZeros {
    public static void main(String[] args) {
        int arr[] = {1,0,0,1,0,0,1,0,0,0,0,1,2,0,5};
        int n = arr.length;
        for(int i=0; i<n; i++) {
            if(arr[i]!=0) {
                System.out.print(arr[i]+ " ");
            }
        }
    }
}
Yori
  • 11
  • 1