- Home /
Remove from HashSet while Looping
Hi
I need to Loop through HashSet, and when condition is met, I need to remove those particular objects from the HashSet, but ofc it`s getting me error that I`m removing stuff from hashset while I`m iterating over it.
I tried this, but the same error it "foreach" line.
HashSet<GameObject> temporaryMyObjects = myObjects; //myObjects is HashSet
foreach (GameObject Object in myObjects)
{
if (Object == player) { continue; }
Vector2 distance = Object.transform.position - player.transform.position;
if (distance.magnitude > 5000)
{
Object.SetActive(false);
temporaryMyObjects .Remove(Object);
}
}
myObjects= temporaryMyObjects ;
Any idea please? I think this should work, but it still says I`m tryin to modify it, even if I`m modifying some other hashset.
Answer by Uldeim · Nov 24, 2014 at 11:00 PM
Unfortunately, HashSets are reference types. Assignment (the = operator) just makes a copy of the reference, but they still point to the same object. So you are, in fact, still iterating over the original HashSet.
I second BoredMormon's suggestion for LINQ, as it is awesome, but it's a slightly different paradigm.
An alternative method is to use the built-in set operators:
HashSet<GameObject> excludedObjects = new HashSet<GameObject>();
foreach (GameObject Object in myObjects)
{
if (Object == player) { continue; }
Vector2 distance = Object.transform.position - player.transform.position;
if (distance.magnitude > 5000)
{
Object.SetActive(false);
excludedObjects .Add(Object);
}
}
//Remove all elements in the second set from the first set.
myObjects.ExceptWith(excludedObjects) ;
Nice it works man thanks !! :DDDDD
No more annoying error.
Note if you are going to call this code frequently or on a large collection it makes sense to use distance.sqr$$anonymous$$agnitude ins$$anonymous$$d of magnitude.
Yes but I experimented all this things I learn on the internet to firstly get transform to variable not call it like transform.position or do sqr$$anonymous$$agnitude :) Tested with 400+ complex AI objects, and it did not make a slight different wether its magnitude or sqr$$anonymous$$agnitude maybe 0.1fps with 500+ AI.
hi Wymmm uh yeah you must be using a computer made after 1970. by "large" he means millions, possibly billions.
Answer by Kiwasi · Nov 24, 2014 at 10:44 PM
You can't add or remove items from a collection while using its enumerator. This is especially true of the Dictionary and HashSet collections, which have no natural order.
Couple of options to solve
Use LINQ to create a new collection with desired elements removed
Store the elements to be removed in a separate collection. Once you have all the items, iterate over the new collection to remove them from the original.
But that`s what I did in my code I have showed. It didn`t work. I created new collection and iterated Over It. But it`s just throws that error even when I do it this separate way.
Your code does not use a new HashSet, it modifies the original. Here is how I would code it.
HashSet<GameObject> objectsToRemove = new HashSet<GameObject> ();
foreach (GameObject Object in myObjects){
if (Object == player) { continue; }
Vector2 distance = Object.transform.position - player.transform.position;
if (distance.magnitude > 5000) {
Object.SetActive(false);
objectsToRemove.Add(Object);
}
}
foreach (GameObject object in objectsToRemove){
myObjects.Remove(object);
}
Answer by Cherno · Nov 24, 2014 at 10:31 PM
You can't remove elements in a foreach loop, but you can by just using a index variable like this:
for (int i = 0; i < myObjects.size; i++)
{
if (myObjects[i] == player) { continue; }
Vector2 distance = myObjects[i].transform.position - player.transform.position;
if (distance.magnitude > 5000)
{
myObjects[i].SetActive(false);
temporaryMyObjects .Remove(myObjects[i]);
}
}
Or temporarily store the current object in a variable
for (int i = 0; i < myObjects.size; i++)
{
GameObject object = myObjects[i];
if (object == player) { continue; }
Vector2 distance = object .transform.position - player.transform.position;
if (distance.magnitude > 5000)
{
object .SetActive(false);
temporaryMyObjects .Remove(object );
}
}
I have never used hashsets but it works with things like Lists, from a quick search I learned that .size get the number of elements of the hashsets so I used that as the iteration limit, dunno if it's actually the right way.
Edit: As for "modifying some other hashset", it seems like you are just referencing the original hashset with a new variable, but this will not create a new hashset, you are in fact directly accessing the original hashset, you just use the reference to access it.
Note that the for approach makes no sense when using a HashSet or Dictionary. These collections have no natural index to use. You need to use for each or manually run through the enumerator with $$anonymous$$oveNext (manual manipulation is not recommended).
Yes youa re right Bored$$anonymous$$ormon. The above loop won`t help since I can`t use [i] with HashSet.
That were my problem lies, I can`t iterate and remove at once.
You could do it like this, then:
Declare a GameObject variable; this will hold the reference to the gameObject that should be removed.
In the foreach loop, once the right go is reached, just assign this one to the go variable above (and continue if you want).
After the loop is finished, just remove the stored go from your hashset.
I guess that's not what you wanted since it used additional code outside the loop, but it's a simple workaround I guess :)
Your answer
Follow this Question
Related Questions
Hashtable used as associative array - how to fetch element value? 2 Answers
Causing a chain reaction and hashtable errors 0 Answers
Return a Hashtable. Warning: Implicit downcast from Object to String. 0 Answers
How do I I convert a hastable to a string? 1 Answer
how to use matrice with unity 3D 1 Answer