91

Given an array of n Objects, let's say it is an array of strings, and it has the following values:

foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";

What do I have to do to delete/remove all the strings/objects equal to "a" in the array?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ramayac
  • 5,173
  • 10
  • 50
  • 58
  • 2
    You can't resize an array in Java. I assume you don't want to just null the elements since that would be trivial. Do you want to shift the other elements to remove the gaps? – Dan Dyer Sep 21 '08 at 23:17
  • 1
    It is trivial, now that I know I can do it. ;) Thanks! – ramayac Sep 21 '08 at 23:55

20 Answers20

115

[If you want some ready-to-use code, please scroll to my "Edit3" (after the cut). The rest is here for posterity.]

To flesh out Dustman's idea:

List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);

Edit: I'm now using Arrays.asList instead of Collections.singleton: singleton is limited to one entry, whereas the asList approach allows you to add other strings to filter out later: Arrays.asList("a", "b", "c").

Edit2: The above approach retains the same array (so the array is still the same length); the element after the last is set to null. If you want a new array sized exactly as required, use this instead:

array = list.toArray(new String[0]);

Edit3: If you use this code on a frequent basis in the same class, you may wish to consider adding this to your class:

private static final String[] EMPTY_STRING_ARRAY = new String[0];

Then the function becomes:

List<String> list = new ArrayList<>();
Collections.addAll(list, array);
list.removeAll(Arrays.asList("a"));
array = list.toArray(EMPTY_STRING_ARRAY);

This will then stop littering your heap with useless empty string arrays that would otherwise be newed each time your function is called.

cynicalman's suggestion (see comments) will also help with the heap littering, and for fairness I should mention it:

array = list.toArray(new String[list.size()]);

I prefer my approach, because it may be easier to get the explicit size wrong (e.g., calling size() on the wrong list).

Community
  • 1
  • 1
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • Glad you liked. I revised my entry to support removing _all_ instances of "a", not just the first. :-) – C. K. Young Sep 21 '08 at 23:38
  • Ooff... shot down at the finish line. Knew I should have kept editing. This system takes some getting used to. Good edit! – Dustman Sep 22 '08 at 01:20
  • GHad: Have you read my Edit2 above? It addresses exactly what you mentioned, and it was posted before your post. – C. K. Young Sep 23 '08 at 02:24
  • 2
    Why not list.toArray(new String[list.size()]) rather than new String[0], since the code will use the new array if it is the correct size? – cynicalman Sep 25 '08 at 01:52
  • Yes, that works. Otherwise, some code (in the Java class library, mainly) store a static instance of String[0] (and other similar zero-sized arrays), and pass the static instances in instead of newing one each time. :-) – C. K. Young Sep 27 '08 at 00:20
  • hi, I am using array.remove function. I want to remove 40320 elements from array and it will be done 9 times in my program execution . It's taking so much time. Is there any efficient method to do that. – Nikhitha Reddy Mar 26 '15 at 06:07
  • This answer is confusing as it has a number of answers to the question and not all of them actually answer the question. Please remove all but the correct answer. – Jason Mar 05 '16 at 16:48
  • For me, The problem is I am trying to convert the list of object array comes from the hibernate native query result to dto directly. And, I solved it using setting values manually from an object array. – S_K Apr 20 '19 at 04:31
33

An alternative in Java 8:

String[] filteredArray = Arrays.stream(array)
    .filter(e -> !e.equals(foo)).toArray(String[]::new);
Vitalii Fedorenko
  • 110,878
  • 29
  • 149
  • 111
  • This should be the accepted answer. Although not pretty considering other programming languages can do this with less and clearer code... this is the best Java has to offer without depending on another library. – Jason Mar 05 '16 at 16:51
  • 8
    Although neat, this is going to be amazingly inefficient compared to System.arraycopy. Probably shouldn't do this in real code. – Bill K May 24 '17 at 16:20
  • if foo is dynamic string variable it's throwing compile time error Local variable foo defined in an enclosing scope must be final or effectively final – Mahender Reddy Yasa Aug 02 '18 at 10:15
  • The question states *"Given an array of n Objects"* — so `Stream.of(foo).filter(s -> ! s.equals("a")).toArray()` would be sufficient. – Kaplan Apr 16 '20 at 11:13
  • More often I only want to [remove the first](https://stackoverflow.com/questions/112503/how-do-i-remove-objects-from-an-array-in-java/66347083#66347083) of several equal entries. – Kaplan Feb 24 '21 at 08:49
21

Make a List out of the array with Arrays.asList(), and call remove() on all the appropriate elements. Then call toArray() on the 'List' to make back into an array again.

Not terribly performant, but if you encapsulate it properly, you can always do something quicker later on.

Dustman
  • 5,035
  • 10
  • 32
  • 40
  • 3
    Re your comment: It's okay, you'll get used to it soon. :-) I posted my post because I didn't want readers to get the idea that elements can be removed from the result of Arrays.asList() (it's an immutable list), so I thought an example could take care of that. :-) – C. K. Young Sep 22 '08 at 05:31
  • Uh, I meant un-resizeable list (add() and remove() do not work). :-P It still has a usable set() method. :-) – C. K. Young Sep 22 '08 at 05:33
  • Though it may seem strange, my experience is that the performance penalty of this approach is minimal. – Marcus Downing Sep 22 '08 at 14:25
  • I'm of the Java 1.4 era, and remember Collections being markedly slower than iterating over arrays. No doubt the introduction of Generics gave Sun ample opportunity to optimize that package. – Dustman Sep 22 '08 at 17:24
  • 8
    What's with this? @Chris pointed out that the list resulting from `Arrays.asList()` doesn't support `remove()`. So is this answer completely invalid? Looks like maybe some comments got removed, so I don't know if this was discussed. – LarsH Mar 22 '12 at 11:16
  • 1
    Both Chris and LarsH are right: array-backed Lists (in other words, those that get created with Arrays.asList()) are structurally immutable which totally invalidates this answer. Yet, as of now, I see seventeen upvotes. Makes one wonder... – Igor Soudakevitch Apr 22 '16 at 15:28
16

You can always do:

int i, j;
for (i = j = 0; j < foo.length; ++j)
  if (!"a".equals(foo[j])) foo[i++] = foo[j];
foo = Arrays.copyOf(foo, i);
7

You can use external library:

org.apache.commons.lang.ArrayUtils.remove(java.lang.Object[] array, int index)

It is in project Apache Commons Lang http://commons.apache.org/lang/

Pritam Banerjee
  • 17,953
  • 10
  • 93
  • 108
bugs_
  • 3,544
  • 4
  • 34
  • 39
6

See code below

ArrayList<String> a = new ArrayList<>(Arrays.asList(strings));
a.remove(i);
strings = new String[a.size()];
a.toArray(strings);
JeffC
  • 22,180
  • 5
  • 32
  • 55
Ali
  • 113
  • 2
  • 10
5

If you need to remove multiple elements from array without converting it to List nor creating additional array, you may do it in O(n) not dependent on count of items to remove.

Here, a is initial array, int... r are distinct ordered indices (positions) of elements to remove:

public int removeItems(Object[] a, int... r) {
    int shift = 0;                             
    for (int i = 0; i < a.length; i++) {       
        if (shift < r.length && i == r[shift])  // i-th item needs to be removed
            shift++;                            // increment `shift`
        else 
            a[i - shift] = a[i];                // move i-th item `shift` positions left
    }
    for (int i = a.length - shift; i < a.length; i++)
        a[i] = null;                            // replace remaining items by nulls

    return a.length - shift;                    // return new "length"
}  

Small testing:

String[] a = {"0", "1", "2", "3", "4"};
removeItems(a, 0, 3, 4);                     // remove 0-th, 3-rd and 4-th items
System.out.println(Arrays.asList(a));        // [1, 2, null, null, null]

In your task, you can first scan array to collect positions of "a", then call removeItems().

einverne
  • 6,454
  • 6
  • 45
  • 91
Alex Salauyou
  • 14,185
  • 5
  • 45
  • 67
  • 1
    Please don't do this. It's confusing, slow and error-prone. Just use System.arraycopy() instead--although bonus points for the fact that if you are going to manipulate an array this way you must track length. – Bill K May 24 '17 at 16:18
4

There are a lot of answers here--the problem as I see it is that you didn't say WHY you are using an array instead of a collection, so let me suggest a couple reasons and which solutions would apply (Most of the solutions have already been answered in other questions here, so I won't go into too much detail):

reason: You didn't know the collection package existed or didn't trust it

solution: Use a collection.

If you plan on adding/deleting from the middle, use a LinkedList. If you are really worried about size or often index right into the middle of the collection use an ArrayList. Both of these should have delete operations.

reason: You are concerned about size or want control over memory allocation

solution: Use an ArrayList with a specific initial size.

An ArrayList is simply an array that can expand itself, but it doesn't always need to do so. It will be very smart about adding/removing items, but again if you are inserting/removing a LOT from the middle, use a LinkedList.

reason: You have an array coming in and an array going out--so you want to operate on an array

solution: Convert it to an ArrayList, delete the item and convert it back

reason: You think you can write better code if you do it yourself

solution: you can't, use an Array or Linked list.

reason: this is a class assignment and you are not allowed or you do not have access to the collection apis for some reason

assumption: You need the new array to be the correct "size"

solution: Scan the array for matching items and count them. Create a new array of the correct size (original size - number of matches). use System.arraycopy repeatedly to copy each group of items you wish to retain into your new Array. If this is a class assignment and you can't use System.arraycopy, just copy them one at a time by hand in a loop but don't ever do this in production code because it's much slower. (These solutions are both detailed in other answers)

reason: you need to run bare metal

assumption: you MUST not allocate space unnecessarily or take too long

assumption: You are tracking the size used in the array (length) separately because otherwise you'd have to reallocate your array for deletes/inserts.

An example of why you might want to do this: a single array of primitives (Let's say int values) is taking a significant chunk of your ram--like 50%! An ArrayList would force these into a list of pointers to Integer objects which would use a few times that amount of memory.

solution: Iterate over your array and whenever you find an element to remove (let's call it element n), use System.arraycopy to copy the tail of the array over the "deleted" element (Source and Destination are same array)--it is smart enough to do the copy in the correct direction so the memory doesn't overwrite itself:

 System.arraycopy(ary, n+1, ary, n, length-n) 
 length--;

You'll probably want to be smarter than this if you are deleting more than one element at a time. You would only move the area between one "match" and the next rather than the entire tail and as always, avoid moving any chunk twice.

In this last case, you absolutely must do the work yourself, and using System.arraycopy is really the only way to do it since it's going to choose the best possibly way to move memory for your computer architecture--it should be many times faster than any code you could reasonably write yourself.

Bill K
  • 62,186
  • 18
  • 105
  • 157
3

Something about the make a list of it then remove then back to an array strikes me as wrong. Haven't tested, but I think the following will perform better. Yes I'm probably unduly pre-optimizing.

boolean [] deleteItem = new boolean[arr.length];
int size=0;
for(int i=0;i<arr.length;i==){
   if(arr[i].equals("a")){
      deleteItem[i]=true;
   }
   else{
      deleteItem[i]=false;
      size++;
   }
}
String[] newArr=new String[size];
int index=0;
for(int i=0;i<arr.length;i++){
   if(!deleteItem[i]){
      newArr[index++]=arr[i];
   }
}
shsteimer
  • 28,436
  • 30
  • 79
  • 95
3

I realise this is a very old post, but some of the answers here helped me out, so here's my tuppence' ha'penny's worth!

I struggled getting this to work for quite a while before before twigging that the array that I'm writing back into needed to be resized, unless the changes made to the ArrayList leave the list size unchanged.

If the ArrayList that you're modifying ends up with greater or fewer elements than it started with, the line List.toArray() will cause an exception, so you need something like List.toArray(new String[] {}) or List.toArray(new String[0]) in order to create an array with the new (correct) size.

Sounds obvious now that I know it. Not so obvious to an Android/Java newbie who's getting to grips with new and unfamiliar code constructs and not obvious from some of the earlier posts here, so just wanted to make this point really clear for anybody else scratching their heads for hours like I was!

Genhis
  • 1,484
  • 3
  • 27
  • 29
DDSports
  • 400
  • 1
  • 14
  • I felt the need to post this, as I often use snippets of code which don't work because I missed something that other coders take for granted. GHad made the point about Array size that got my code working (thanks for making that clear). Trying stuff out is the way to learn, and if that means I deserve all I get for taking code from SO and trying to understand how/why it works, then so be it. As an unpaid amateur, I'm not the Java genius that some like to think they are! Thankfully, most of the SO contributors answer questions to help others write better code: For that, you deserve thanks! – DDSports Jul 05 '13 at 14:24
2

Initial array

   int[] array = {5,6,51,4,3,2};

if you want remove 51 that is index 2, use following

 for(int i = 2; i < array.length -1; i++){
    array[i] = array[i + 1];
  }
Ebin Joy
  • 2,690
  • 5
  • 26
  • 39
1

EDIT:

The point with the nulls in the array has been cleared. Sorry for my comments.

Original:

Ehm... the line

array = list.toArray(array);

replaces all gaps in the array where the removed element has been with null. This might be dangerous, because the elements are removed, but the length of the array remains the same!

If you want to avoid this, use a new Array as parameter for toArray(). If you don`t want to use removeAll, a Set would be an alternative:

        String[] array = new String[] { "a", "bc" ,"dc" ,"a", "ef" };

        System.out.println(Arrays.toString(array));

        Set<String> asSet = new HashSet<String>(Arrays.asList(array));
        asSet.remove("a");
        array = asSet.toArray(new String[] {});

        System.out.println(Arrays.toString(array));

Gives:

[a, bc, dc, a, ef]
[dc, ef, bc]

Where as the current accepted answer from Chris Yester Young outputs:

[a, bc, dc, a, ef]
[bc, dc, ef, null, ef]

with the code

    String[] array = new String[] { "a", "bc" ,"dc" ,"a", "ef" };

    System.out.println(Arrays.toString(array));

    List<String> list = new ArrayList<String>(Arrays.asList(array));
    list.removeAll(Arrays.asList("a"));
    array = list.toArray(array);        

    System.out.println(Arrays.toString(array));

without any null values left behind.

Taryn
  • 242,637
  • 56
  • 362
  • 405
GHad
  • 9,611
  • 6
  • 34
  • 40
  • Nice try, but no cigar. I posted an edit on exactly this topic, way before you made your post. So, although you're "technically correct", I don't appreciate your trying to get people to displace my post. I just thought you should know that. – C. K. Young Sep 23 '08 at 02:29
  • It's not about post displacement, but about avoiding errors and dangerous code. Greetz GHad – GHad Sep 23 '08 at 06:10
  • Errors can be avoided if people read my whole post (including both addenda). If people just cut and paste code without thinking, then they deserve everything they get. Programmers get paid what they do because they exercise their brains...I hope. [continues] – C. K. Young Sep 24 '08 at 10:50
  • 1
    [continued] Your code is "dangerous" too if people aren't cognisant of the fact that by using a hash, the items become disordered. Of course, _thinking_ programmers realise this, but if you call my code dangerous because people cut and paste without thinking, it's only fair to say the same of yours. – C. K. Young Sep 24 '08 at 10:53
  • Sure, you're right about the hash. And as the point is clear by your 2nd edit, I must have overread this. As said, just wanted to avoid an array with null values and duplication. You may change your code based upon your 2nd edit and leave a comment in Edit3 about the array. Didn't want to attack you – GHad Sep 24 '08 at 16:37
  • Thanks for that. I've added a whole section on how to prevent heap littering, too, that you may be interested in. See source for java.util.EnumSet for an example of this usage. – C. K. Young Sep 27 '08 at 00:36
1

My little contribution to this problem.

public class DeleteElementFromArray {
public static String foo[] = {"a","cc","a","dd"};
public static String search = "a";


public static void main(String[] args) {
    long stop = 0;
    long time = 0;
    long start = 0;
    System.out.println("Searched value in Array is: "+search);
    System.out.println("foo length before is: "+foo.length);
    for(int i=0;i<foo.length;i++){ System.out.println("foo["+i+"] = "+foo[i]);}
    System.out.println("==============================================================");
    start = System.nanoTime();
    foo = removeElementfromArray(search, foo);
    stop = System.nanoTime();
    time = stop - start;
    System.out.println("Equal search took in nano seconds = "+time);
    System.out.println("==========================================================");
    for(int i=0;i<foo.length;i++){ System.out.println("foo["+i+"] = "+foo[i]);}
}
public static String[] removeElementfromArray( String toSearchfor, String arr[] ){
     int i = 0;
     int t = 0;
     String tmp1[] = new String[arr.length];     
         for(;i<arr.length;i++){
              if(arr[i] == toSearchfor){     
              i++;
              }
             tmp1[t] = arr[i];
             t++;
     }   
     String tmp2[] = new String[arr.length-t];   
     System.arraycopy(tmp1, 0, tmp2, 0, tmp2.length);
     arr = tmp2; tmp1 = null; tmp2 = null;
    return arr;
}

}

Andre
  • 172
  • 2
  • 8
  • This is a really good answer although your great test code makes it look a lot bigger than it actually is. The entire solution could be a single line arraycopy (assuming you use the same array which is what you'd want to do if you were working so close to the metal you were using arrays instead of collections). – Bill K May 24 '17 at 16:22
  • thank you, i wrote it so readers can see a bit what goes on under the hood and test it, now i look at it again System.arraycopy(tmp1, 0, tmp2, 0, tmp2.length) ; can be removed and replaced by something like for(i = 0; i < (arr.length - t); i++){ tmp2[i] = tmp1[i]; } you can also create a byte buffer and copy 8 bytes at a time on a 64bit machine to gain extra copy performance – Andre Jun 05 '17 at 10:08
0

Arrgh, I can't get the code to show up correctly. Sorry, I got it working. Sorry again, I don't think I read the question properly.

String  foo[] = {"a","cc","a","dd"},
remove = "a";
boolean gaps[] = new boolean[foo.length];
int newlength = 0;

for (int c = 0; c<foo.length; c++)
{
    if (foo[c].equals(remove))
    {
        gaps[c] = true;
        newlength++;
    }
    else 
        gaps[c] = false;

    System.out.println(foo[c]);
}

String newString[] = new String[newlength];

System.out.println("");

for (int c1=0, c2=0; c1<foo.length; c1++)
{
    if (!gaps[c1])
    {
        newString[c2] = foo[c1];
        System.out.println(newString[c2]);
        c2++;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

It depends on what you mean by "remove"? An array is a fixed size construct - you can't change the number of elements in it. So you can either a) create a new, shorter, array without the elements you don't want or b) assign the entries you don't want to something that indicates their 'empty' status; usually null if you are not working with primitives.

In the first case create a List from the array, remove the elements, and create a new array from the list. If performance is important iterate over the array assigning any elements that shouldn't be removed to a list, and then create a new array from the list. In the second case simply go through and assign null to the array entries.

DJClayworth
  • 26,349
  • 9
  • 53
  • 79
0

Will copy all elements except the one with index i:

if(i == 0){
                System.arraycopy(edges, 1, copyEdge, 0, edges.length -1 );
            }else{
                System.arraycopy(edges, 0, copyEdge, 0, i );
                System.arraycopy(edges, i+1, copyEdge, i, edges.length - (i+1) );
            }
PauLy
  • 79
  • 7
0

If it doesn't matter the order of the elements. you can swap between the elements foo[x] and foo[0], then call foo.drop(1).

foo.drop(n) removes (n) first elements from the array.

I guess this is the simplest and resource efficient way to do.

PS: indexOf can be implemented in many ways, this is my version.

Integer indexOf(String[] arr, String value){
    for(Integer i = 0 ; i < arr.length; i++ )
        if(arr[i] == value)
            return i;         // return the index of the element
    return -1                 // otherwise -1
}

while (true) {
   Integer i;
   i = indexOf(foo,"a")
   if (i == -1) break;
   foo[i] = foo[0];           // preserve foo[0]
   foo.drop(1);
}
milevyo
  • 2,165
  • 1
  • 13
  • 18
0

to remove  only the first  of several equal entries
with a lambda

boolean[] done = {false};
String[] arr = Arrays.stream( foo ).filter( e ->
  ! (! done[0] && Objects.equals( e, item ) && (done[0] = true) ))
    .toArray(String[]::new);

can remove null entries

Kaplan
  • 2,572
  • 13
  • 14
-1

In an array of Strings like

String name = 'a b c d e a f b d e' // could be like String name = 'aa bb c d e aa f bb d e'

I build the following class

class clearname{
def parts
def tv
public def str = ''
String name
clearname(String name){
    this.name = name
    this.parts = this.name.split(" ")
    this.tv = this.parts.size()
}
public String cleared(){

        int i
        int k
        int j=0        
    for(i=0;i<tv;i++){
        for(k=0;k<tv;k++){
            if(this.parts[k] == this.parts[i] && k!=i){
               this.parts[k] = '';
                j++
            }
        }
    }
    def str = ''
    for(i=0;i<tv;i++){
        if(this.parts[i]!='')

           this.str += this.parts[i].trim()+' '
    } 
    return this.str    
}}



return new clearname(name).cleared()

getting this result

a b c d e f

hope this code help anyone Regards

Orlando Reyes
  • 93
  • 1
  • 3
-7

Assign null to the array locations.

alfinoba
  • 723
  • 1
  • 6
  • 14