Reputation: 1795
I am removing things from an arraylist while inside a loop. I noticed that when I have two things in a row that need to be removed, it misses the second one. For example, my code checks whether a number in the arraylist is smaller than a static number. I have:
arraylist[2,5,15,30]
and I am checking it against
check = 10
so I have a loop
for (int i=0;i<arraylist.size();i++){
if(check > arraylist.get(i){
arraylist.remove(i);
}
}
I am pretty sure I am missing the second one because originally my arraylist is numbered this way:
0,1,2, 3
arraylist[2,5,15,30]
And after it removes the first entry it changes it to:
0,1, 2
arraylist[5,15,30]
And I already checked 0, so I don't need to check it again. Is there a simple way to go about fixing this? Without changing my data structure? Thanks
Upvotes: 0
Views: 112
Reputation: 8974
You could use Iterator or ListIterator. Those interfaces let's you iterate and remove over the collection in one step almost.
Sample Test:
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class ListIteratorTest {
List<Integer> list;
@Before
public void setUp() {
list = new ArrayList<>();
list.add(2);
list.add(5);
list.add(15);
list.add(30);
}
@Test
public void testListIterator() {
ListIterator<Integer> lit = list.listIterator();
while(lit.hasNext()){
int val = lit.next();
if(val > 10){
lit.remove();
}
}
assertFalse(list.contains(15));
}
}
Upvotes: 1
Reputation: 41210
There are three ways to do this.
Use an Iterator<> - there is a remove() function on it which will allow you to remove the current item and the iterator will keep track of tihngs.
Start at the end of the list and iterate backwards.
When you remove the item move your current index left 1.
All of these cases will be quite inefficient if you are removing a lot of items though as you are shuffling the whole list along each time you remove one item. Better would be to do:
// Scan through the array keeping a "read" pointer and a "write" pointer.
int write = 0;
for (int scan=0;scan<arrayList.size();scan++) {
Integer i arrayList.get(scan);
// Only copy items that match the check
if (check <= i) {
if (scan != write) {
arrayList.set(write, i);
}
write++;
}
}
// Remove any "dead" entries from the end of the list
while (arrayList.size() > write) {
arrayList.remove(arrayList.size()-1);
}
Otherwise for every element you remove every other element after that one gets shuffled along. With this code each element only gets shuffled along once no matter how many spots it needs to move by.
Upvotes: 0
Reputation: 42174
Either use an iterator or loop through the ArrayList backwards.
Upvotes: 4
Reputation: 10233
You can subtract i
by one each time you remove an item from the ArrayList, like this:
for (int i=0;i<arraylist.size();i++){
if(check > arraylist.get(i){
arraylist.remove(i);
i = i--;
}
}
Upvotes: 1
Reputation: 136132
Use Iterator
for (Iterator<Integer> it = list.iterator(); it.hasNext();) {
if (check > it.next()) {
it.remove();
}
}
Upvotes: 1
Reputation: 1847
Take a look at ArrayList#remove it says:
Removes the element at the specified position in this list. Shifts any subsequent elements to the left (subtracts one from their indices).
So you can either do it backward or whenever you delete an element decrement your loop counter
Upvotes: 1