I'm studying OOP, and I came across array lists. I'd like to know how the remove() function actually works, and what is the most efficient way to use it.
First method to delete all the "BB"
public class ArrayListTest {
public static void main(String args[]){
ArrayList<String> Alist = new ArrayList<String>();
Alist.add("AA");
Alist.add("BB");
Alist.add("AA");
Alist.add("AA");
Alist.add("AA");
Alist.add("BB");
System.out.println("Original ArrayList : " + Alist);
int n = 0 ;
for (int i = 0; i < Alist.size(); i++){
n++;
Alist.remove("BB");
}
System.out.println(n);
System.out.println("Modified ArrayList : " + Alist);
}
}
The output
run:
Original ArrayList : [AA, BB, AA, AA, AA, BB]
4
Modified ArrayList : [AA, AA, AA, AA]
BUILD SUCCESSFUL (total time: 0 seconds)
Secend Method to delete all the "BB"
public class ArrayListTest {
public static void main(String args[]){
ArrayList<String> Alist = new ArrayList<String>();
Alist.add("AA");
Alist.add("BB");
Alist.add("AA");
Alist.add("AA");
Alist.add("AA");
Alist.add("BB");
System.out.println("Original ArrayList : " + Alist);
int n = 0 ;
while(Alist.contains("BB")){
n++;
Alist.remove("BB");
}
System.out.println(n);
System.out.println("Modified ArrayList : " + Alist);
}
}
The output
run:
Original ArrayList : [AA, BB, AA, AA, AA, BB]
2
Modified ArrayList : [AA, AA, AA, AA]
BUILD SUCCESSFUL (total time: 0 seconds)
It's confusing because the counter was triggered to increase a few more times in the first one, but is it actually more efficient, or is the "contains()" looping through the whole array list at each check on the statement behind the scene.
The most efficient way to delete from an arraylist is probably:
Alist.removeAll(Collections.singleton("BB"))
or
Alist.removeIf("BB"::equals)
These methods can be more efficient than individual calls to remove
because the actual deletion can be deferred until all elements equal to "BB"
have been identified.
This is important because removing an element from an ArrayList
shifts all of the elements with larger index "down by one". In the worst case (when all the list elements are equal to the thing you want to remove), individual list removal calls would be quadratic in the number of list elements; removeAll
or removeIf
would be linear, because they can shift the non-deleted elements just once, and not bother shifting the to-be-deleted elements at all.
The most obvious inefficiency in the first method is that you call remove
as many times as there are list elements, irrespective of how many times the item appears in the list. In a particularly pathological example, you could have 1M elements in the list, where none of them are equal to "BB"
: you'd still call remove
1M times.
The most obvious inefficiency in the second method is that you invoke contains
and then remove
. You're looking up the element twice by doing this.
A more efficient method - but still less efficient than the two methods at the start of this answer - would be to use the return value of remove
, which is a boolean indicating whether an element was actually removed. Once remove
returns false
, there is no point in calling remove
again, because the element isn't found:
while (Alist.remove("BB")) {}