Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Adding to a list is looping and continues to populate the list.

Discussion in 'Scripting' started by atomicWedgie, Apr 3, 2014.

  1. atomicWedgie

    atomicWedgie

    Joined:
    Jan 28, 2014
    Posts:
    19
    Hello.
    I have a list of GameObjects.
    Code (csharp):
    1. public List<GameObject> ObjectList = new List<GameObject>();
    I loop thru that list with a foreach loop. I am looking for red color game objects.
    Code (csharp):
    1. foreach(GameObject go in ObjectList)
    2. {
    3. if(go.renderer.material.color == Color.red)
    4. {
    5.  
    6. }
    7.  
    8. }
    I want to remove the red game objects from that list. so i make another list.
    Code (csharp):
    1. public List<GameObject> ToRemove = new List<GameObject>();
    I am going to add the red game objects to the list called "ToRemove".
    Code (csharp):
    1. foreach(GameObject go in ObjectList)
    2. {
    3. if(go.renderer.material.color == Color.red)
    4. {
    5. ToRemove.Add(go);
    6. }
    7.  
    8. }
    The problem is that "ToRemove.Add(go)" loops and continues to add objects even if only one red game object in found in the list.
    I am watching both lists in the inspector. This is in a method called void ObjectCount(), and is called from the update.I understand that its looping because of the update, but i don't understand where else or how else to do it. The foreach doesn't loop thru the game objects if it not in the update.
     
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    There's no code where you are enumerating ToRemove and removing items from ObjectList
     
  3. atomicWedgie

    atomicWedgie

    Joined:
    Jan 28, 2014
    Posts:
    19
    I havnt enumerated thru the ToRemove list yet. The red objects are not being added to the ToRemove list properly. A red object is found and removed from the ObjectList. When said red object is added to the ToRemove list it is added hundreds of time. Every update. How would i use ToRemove.add for only the red objects found.
     
  4. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Again - there is no code removing anything from ObjectList which means that it would be added to ToRemove every frame.
     
  5. atomicWedgie

    atomicWedgie

    Joined:
    Jan 28, 2014
    Posts:
    19
    Ok. That works but how do I handle the "Collection was modified" error for the ObjectList list.
    I'm trying to modify the list while enumerating thru it.
    Code (csharp):
    1. foreach(GameObject go in ObjectList)
    2. {
    3. if(go.renderer.material.color == Color.red)
    4. {
    5. ObjectList.Remove (go);
    6. ToRemove.Add (go);
    7. }
    8. }
     
  6. dmitche3

    dmitche3

    Joined:
    Apr 3, 2014
    Posts:
    23
    First let me say that I'm a noob to Unity. I think that the code below that you posted won't work as is because you are modifying the list as you try to parse it.
    1.foreach(GameObject go in ObjectList)
    2.{
    3.if(go.renderer.material.color == Color.red)
    4.{
    5.ObjectList.Remove (go);
    6.ToRemove.Add (go);
    7.}


    I believe the solution is to do something like this to your foreach loop. By doing this 'trick' you're casting ToList() and you're making a copy of the keys to the list and you can enumerate on that so deleting entries doesn't impact the loop.

    foreach (GameObject go in ObjectList.Keys.Cast<GameObject>().ToList())
    {}
     
  7. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,749
    this is not possible as any change on the collection invalidates the enumerator. so your initial approach of adding the objects to remove to an additional list and iterate over it and remove the objects in it in the source list is the way to go. i don't really understand your problem/question. do you call this method in an update? what do you want to achieve?
     
  8. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    Do the test in reverse.

    For I = list.count - 1 to 0

    This will avoid enumeration problems
     
  9. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    The whole point of adding to another list is to not do the remove in the enumeration. Enumerate ObjectList and add to ToRemove and then enumerate ToRemove and remove from ObjectList. Or use a for loop that counts backwards from the last item in the list.
     
  10. atomicWedgie

    atomicWedgie

    Joined:
    Jan 28, 2014
    Posts:
    19
    Thanks for your reply. I understand that i cant modify it that way. Thus the idea of two lists. I was mearly trying another suggestion and posting my results. I may have misunderstood, but already knew that would not work. To clarify my problem for you..
    I am looking for a red object in the first list called ObjectList. I m using a foreach to do that. In the inspector I can watch that list populate. For example, I know that while im watching this there is only one red object that can be found. The others in the list are of other colors. The red object is found by the foreach and is added to the new list called ToRemove. The problem lies here : In my example one red object exists, but it populates the ToRemove list until i stop the project. That can be hundreds. One red object found in the first list does not equal one red object added the next list called ToRemove. This is happening in a method, that is called by the Update. I tried moving it out of update but then the foreach does not loop.
     
  11. atomicWedgie

    atomicWedgie

    Joined:
    Jan 28, 2014
    Posts:
    19
    My above response was directed toward user: exiguous
     
  12. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Code (csharp):
    1.  
    2. foreach (var go in ObjectList)
    3. {
    4.     if (go.renderer.material.color == Color.red)
    5.         ToRemove.Add(go);
    6. }
    7.  
    8. foreach (var go in ToRemove)
    9. {
    10.     ObjectList.Remove(go);
    11. }
    12. ToRemove.Clear();
    13.  
    Or

    Code (csharp):
    1.  
    2. for (int i = ObjectList.Count - 1; i >= 0; i--)
    3. {
    4.     if (ObjectList[i].renderer.material.color == Color.red)
    5.         ObjectList.RemoveAt(i);
    6. }
    7.  
     
  13. atomicWedgie

    atomicWedgie

    Joined:
    Jan 28, 2014
    Posts:
    19
    KelsoMRK thanks for your reply. I will try this out later. Why var instead of GameObject? I have only seen that used in unityscript.
     
  14. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,664
    It works in some cases within C# as well. Would be exactly the same if you just specified the type there...
     
  15. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    If you're immediately assigning a value to a variable you can use var. I just used it here for brevity.

    Code (csharp):
    1.  
    2. var thing = new GameObject(); // works
    3. var thing = GetTheThing(); // works but not very clear
    4. var thing; // doesn't work
    5.  
     
  16. atomicWedgie

    atomicWedgie

    Joined:
    Jan 28, 2014
    Posts:
    19
    KelsoMRK. That worked great. Thanks. Can these forum posts be marked as solved?
     
  17. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Nope - but thanks for replying back that it worked!