0

Let's say we have an ArrayList of Cats.

This is our cat:

public class Cat{
   String color;
   int age;
   public Cat(String color, int age){
       this.color = color;
       this.age = age;
   }
 }

We have a cat and each cat has a color. Somewhere else in our code, we have the following:

 ArrayList<Cat>cats = new ArrayList<Cat>();
 cats.add(new Cat("white",5);
 cats.add(new Cat("black",6);
 cats.add(new Cat("orange",10);
 cats.add(new Cat("gray",3);
 System.out.println(cats.size()); prints out 4

So now are cats ArrayList has 4 cats in it. What if I want to remove all cats that are over 5 years old, shouldn't I be able to do the following?

for(int index = 0; index<cats.size(); index++){
    if(cats.get(index).age > 5){
        cats.remove(index);
    }
}

Now after that runs, I print out the size of the cats ArrayList and it says 3, even though it should remove 3 Cats and leave one.

So, shouldn't this work? I don't understand why it wouldn't. What other ways are there to remove objects with specific values from a List/Array?

Daneel Rakow
  • 81
  • 1
  • 1
  • 9
  • See the link above mine. tl;dr: use an iterator. – Ricky Mutschlechner Nov 30 '16 at 00:54
  • @TimBiegeleisen What does this have to do with a CoMod exception? – shmosel Nov 30 '16 at 00:54
  • No, you cannot do it this way. Think about it: if you iterate the items and delete one in the middle of the loop, the index of the next items will change, and thus skips one each time. What it does is: the first one is skipped, because the age is 5. The second one is deleted, index is 1, size() is 3 after deleting. So in the next step, index is 2, but this is now "gray" and not orange. Gray is 3, thus not deleted. After that, index = 3 and size() = 3, so the loop is terminated, leaving you with 3 items: white, orange and gray. – Lupinity Labs Nov 30 '16 at 00:54
  • 1
    And the solution is to decrement `index` after removing. Or use an iterator. – shmosel Nov 30 '16 at 00:55
  • @shmosel: did you really just suggest that? :-) It would be ok to have the loop decrementing, thus deleting from last to first item. However, as everyone said: just use an iterator. – Lupinity Labs Nov 30 '16 at 00:57
  • @Lupinity I didn't mean to loop backwards. I meant MDragon00's solution. – shmosel Nov 30 '16 at 00:59
  • I would call that bad coding style tbh. – Lupinity Labs Nov 30 '16 at 00:59
  • I suggest that you use a debugger to step through your code and inspect the contents of your list and the values of other variables. – Code-Apprentice Nov 30 '16 at 01:00
  • I wouldn't call this question a duplicate by the way, especially an "exact duplicate" whatsoever – DragonJawad Nov 30 '16 at 01:06
  • However, that does answer this aspect: "What other ways are there to remove objects with specific values from a List/Array?" – DragonJawad Nov 30 '16 at 01:07

1 Answers1

0

The issue with your example is that you're removing an item from the cats array but not accounting for the new size. What's happening is this:

  • i = 0. Cat is "white", age is 5, so nothing to do
  • i = 1. Cat is "black", age is 6. Removed item at index 1 (now size is 3 and index 1 is "orange")
  • i = 2. Cat is "gray", age is 3, so nothing to do
  • i = 3, which is not less than the size of cats (which is 3), so don't enter for loop again

If you're sure you want to use a for loop, the easiest solution would be to decrement the index by one every time you remove an element, like so:

for(int index = 0; index<cats.size(); index++){
   if(cats.get(index).age > 5){
       cats.remove(index);
       index = index - 1; // Accounting for index of elements ahead changing by one
   }
}
DragonJawad
  • 1,846
  • 3
  • 20
  • 28
  • 1
    Wow, this is one dirty solution. Why not do a `for (int index = cats.size()-1; index >= 0; index--) {}` loop instead? It's at least a little bit cleaner... – Lupinity Labs Nov 30 '16 at 00:59
  • "i = 1. Cat is "black", age is 6. Remove item at index 2 (now size is 3 and index 1 is "orange")" Do you mean Remove item at index 1? – Code-Apprentice Nov 30 '16 at 00:59
  • @Lupinity It may not be the best approach, but it requires the least modification to OP's code. – shmosel Nov 30 '16 at 00:59
  • Thanks for the correction @Code-Apprentice, edited it in – DragonJawad Nov 30 '16 at 01:00
  • I think we should strive to provide the best approach, not the easiest. – Lupinity Labs Nov 30 '16 at 01:00
  • @Lupinity I think both solutions are relevant, since part of OP's question was trying to understand the problem with a standard increment. The "easy" solution helps clarify the issue. – shmosel Nov 30 '16 at 01:04
  • @Lupinity Your solution is definitely better than mine that falls within the question itself. If you'd like me to edit in your solution as well, let me know and I'll append it – DragonJawad Nov 30 '16 at 01:05