- Home /
Remove Missing Objects from List
I have a list that is being monitored for it's length:
var item_black : List.<GameObject>;
Some of the items placed in that list, sometimes get destroyed by the game, and I end up with a bunch of missing entries. One easy way I thought of clearing this is:
function FixedUpdate () {
for (var sweetie : GameObject in item_black) if (sweetie == null) item_black.Remove(sweetie);
}
This actually works, but Unity throws an error:
InvalidOperationException: Collection was modified; enumeration operation may not execute.
System.Collections.Generic.List`1+Enumerator[UnityEngine.GameObject].VerifyState () (at /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System.Collections.Generic/List.cs:778)
System.Collections.Generic.List`1+Enumerator[UnityEngine.GameObject].MoveNext () (at /Users/builduser/buildslave/monoAndRuntimeClassLibs/build/mcs/class/corlib/System.Collections.Generic/List.cs:784)
item_toucher.FixedUpdate () (at Assets/my_script.js:55)
Whats the safest way of doing this? Do I need to remove the game objects explicitly back to this script as and when they are removed, or is there a way to do a RemoveAll(null list) or RemoveAt(null list) in UnityScript?
Answer by vexe · Sep 14, 2014 at 06:58 AM
You can't use a foreach loop to modify the contents of what you're enumerating (see this video for all the syntatic sugars behind foreach)
I would use LINQ for that:
myList = myList.Where(item => item != null).ToList();
I think the syntax for JS is:
myList = myList.Where(function(item) { return item != null }).ToList();
Another way to do it, is to iterate on your list backwards with a for loop, not foreach
for(var i = list.Count - 1; i > -1; i--)
{
if (list[i] == null)
list.RemoveAt(i);
}
Hi thanks for the quick reply, great community this is.
The backwards counting for loop worked a treat, thanks a lot!
Woah the backwards iterating trick is awesome. I have never thought of that.
Wow thanks! Worked perfectly for my situation where when the count hit a certain number it would fire an event.
Hey @vexe , thanks for the solution here, very helpful! I know this is an old one, but figure I'll ask just in case. Would you $$anonymous$$d explaining why this needs to iterate backwards? What would be wrong with starting at index 0 and incrementing until you hit the list count -1?
@myazuid The reason is that when you remove an item from the list, you change the placement of every item after it. So if you're are iterating going from 0 => n-1, when you remove an item you now are in a different place in the list. Going from n-1 => 0 works because the list indexes are changing past where you are in the list.
Answer by toomasio · Sep 16, 2016 at 10:54 AM
listItems.RemoveAll(item => item == null);
So if you have a GameObject list:
gos.RemoveAll(GameObject => GameObject == null);
Answer by eagleeyez · Jul 24, 2020 at 04:32 PM
WOW, iterate on your list backwards with a for loop, not foreach
That solved my very big headache. Thank you.