42

I have a bunch of indexes and I want to remove elements at these indexes from an ArrayList. I can't do a simple sequence of remove()s because the elements are shifted after each removal. How do I solve this?

16 Answers 16

50

To remove elements at indexes:

Collections.sort(indexes, Collections.reverseOrder());
for (int i : indexes)
    strs.remove(i);

Or, using the Stream API from Java 8:

indexes.sort(Comparator.reverseOrder());
indexes.stream().mapToInt(i -> i).forEach(l::remove);
Sign up to request clarification or add additional context in comments.

1 Comment

Arrays.sort() if dealing with arrays ^^
37

Sort the indices in descending order and then remove them one by one. If you do that, there's no way a remove will affect any indices that you later want to remove.

How you sort them will depend on the collection you are using to store the indices. If it's a list, you can do this:

List<Integer> indices;
Collections.sort(indices, new Comparator<Integer>() {
   public int compare(Integer a, Integer b) {
      //todo: handle null
      return b.compareTo(a);
   }
}

Edit

@aioobe found the helper that I failed to find. Instead of the above, you can use

Collections.sort(indices, Collections.reverseOrder());

5 Comments

No need to reinvent the reverse reverse comparator. See my answer.
@aioobe:Thanks, I thought there was a way to do it within the Collections API but I was having trouble finding it.
Arrays.sort() if you have an array ^^
I don't understand. In what way does sorting an array change the fact that things need to be shifted? For example, if the array was { 8, 5, 9, 1, 4, 7 } The user wants to remove 1, 5, and 4. If you reverse sort the array to: { 9, 8, 7, 5, 4, 1 } you are no closer to accomplishing your goal.
@Hatefiend: I didn't say to sort the values, I said sort the indices. So in your example, the indices would be 1, 3, 4. Sorted would be [4, 3, 1]. Removing them in that order means that the indices of subsequent removals will still be valid. After removing 4 (at index 4), 5 and 1 will still be at index 1 and 3 respectively. And so on.
20

I came here for removing elements in specific range (i.e., all elements between 2 indexes), and found this:

list.subList(indexStart, indexEnd).clear()

2 Comments

The subList() method of java.util.ArrayList class is used to return a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations.
this works because structural changes apparently also are reflected in the backing list via the protected removeRange method. stackoverflow.com/a/65005722/1527469
5

You can remove the elements starting from the largest index downwards, or if you have references to the objects you wish to remove, you can use the removeAll method.

Comments

4

you might want to use the subList method with the range of index you would like to remove and then call clear() on it.

(pay attention that the second parameter is exclusive - for example in this case, I pass 2 meaning only index 0 and 1 will be removed.):

public static void main(String[] args) {
    ArrayList<String> animals = new ArrayList<String>();
    animals.add("cow");
    animals.add("dog");
    animals.add("chicken");
    animals.add("cat");
    animals.subList(0, 2).clear();
    for(String s : animals)
        System.out.println(s);
}

}

the result will be: chicken cat

1 Comment

thanks! this is a good List range operation to get a subList from a List. documentation for the method -> docs.oracle.com/javase/7/docs/api/java/util/…, int)
3

You can remove the indexes in reverse order. If the indexes are in order like 1,2,3 you can do removeRange(1, 3).

2 Comments

It seems not possible to use the removeRange method as long as you don't extend ArrayList, because the method is protected.
@SanghyunLee Why it is protected though ?
2

I think nanda was the correct answer.

List<T> toRemove = new LinkedList<T>();
for (T t : masterList) {
  if (t.shouldRemove()) {
    toRemove.add(t);
  }
}

masterList.removeAll(toRemove);

1 Comment

This is a poor solution. Better to use docs.oracle.com/javase/6/docs/api/java/util/…
1

You can sort the indices as many said, or you can use an iterator and call remove()

List<String> list = new ArrayList<String>();
    list.add("0");
    list.add("1");
    list.add("2");
    list.add("3");
    list.add("4");
    list.add("5");
    list.add("6");
    List<Integer> indexes = new ArrayList<Integer>();
    indexes.add(2);
    indexes.add(5);
    indexes.add(3);
    int cpt = 0;
    Iterator<String> it = list.iterator(); 
    while(it.hasNext()){
        it.next();
        if(indexes.contains(cpt)){
            it.remove();
        }
        cpt++;
    }

it depends what you need, but the sort will be faster in most cases

1 Comment

I just had a case where I could eliminate the list of indexes, because they where a workaround to remember the rows to remove. Iterator.remove is cool and can solve some remove problems easily and fast.
1

Use guava! The method you are looking is Iterators.removeAll(Iterator removeFrom, Collection elementsToRemove)

1 Comment

I think he has indices, not the real elements. So this is not helping imo.
1

If you have really many elements to remove (and a long list), it may be faster to iterate over the list and add all elements who are not to be removed to a new list, since each remove()-step in a array-list copies all elements after the removed one by one. In this case, if you index list is not already sorted (and you can iterate over it parallel to the main list), you may want to use a HashSet or BitSet or some similar O(1)-access-structure for the contains() check:

/**
 * creates a new List containing all elements of {@code original},
 * apart from those with an index in {@code indices}.
 * Neither the original list nor the indices collection is changed.
 * @return a new list containing only the remaining elements.
 */
public <X> List<X> removeElements(List<X> original, Collection<Integer> indices) {
    // wrap for faster access.
    indices = new HashSet<Integer>(indices);
    List<X> output = new ArrayList<X>();
    int len = original.size();
    for(int i = 0; i < len; i++) {
       if(!indices.contains(i)) {
           output.add(original.get(i));
       }
    }
    return output;
}

Comments

0

order your list of indexes, like this

if 2,12,9,7,3 order desc to 12,9,7,3,2

and then do this

for(var i = 0; i < indexes.length; i++) { source_array.remove(indexes[0]); }

this should resolve your problem.

Comments

0

If the elements you wish to remove are all grouped together, you can do a subList(start, end).clear() operation.

If the elements you wish to remove are scattered, it may be better to create a new ArrayList, add only the elements you wish to include, and then copy back into the original list.

Edit: I realize now this was not a question of performance but of logic.

2 Comments

.clear() returns void (in typical java fashion)...how would you retain your sublist (if you needed to)
@Jason List sublist = list.subList(start, end); List removed = new List(subList); subList.clear();
0

If you want to remove positions X to the Size

//a is the ArrayList
a=(ArrayList)a.sublist(0,X-1);

Comments

0

Assuming your indexes array is sorted (eg: 1, 3, 19, 29), you can do this:

for (int i = 0; i < indexes.size(); i++){
   originalArray.remove(indexes.get(i) - i);
}

Comments

0

A more efficient method that I guess I have not seen above is creating a new Arraylist and selecting which indices survive by copying them to the new array. And finally reassign the reference.

Comments

0

I ended up here for a similar query and @aioobe's answer helped me figure out the solution. However, if you are populating the list of indices to delete yourself, might want to consider using this:

indices.add(0, i);

This will eliminate the need for (the costly) reverse-sorting of the list before iterating over it, while removing elements from the main ArrayList.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.