Many times i’m programming and i want to iterate a collection and modify it. Thsi usually happens when i want to remove a certain number of objects of a collection:
foreach( Element e in elements){
if( ConditionIsSatisfied(e) ) {
elements.Remove(e);
}
}
The above method will give a collection modified exception because i’m modifying a collection while iterating it.
To resolve this problem without long lines of code, there is a simple thing i can do:
List<Element> temporayElements = new List<Element>(elements);
foreach( Element e in temporayElements){
if( ConditionIsSatisfied(e) ) {
elements.Remove(e);
}
}
This way, i can iterate and check the conditions in one container and manipulate the original one without the possibility of throwing a “Collection was modified” exception.
Interestingly, I usually go for a different approach:
List toRemove = new List();
foreach( Element e in elements){
if( ConditionIsSatisfied(e) ) {
toRemove.Add(e);
}
}
foreach( Element e in toRemove){
elements.Remove(e)
}
From where I see it, this spares memory, and is probably not heavier on the computation side (your code may also have a hidden foreach cycle in that constructor
).
Alternatively, use Iterator.remove():
[code]
for (Iterator it = elements.iterator(); it.hasNext();) {
if (ConditionIsSatisfied(e) ) {
it.remove();
}
}
[/code]
This works even if you have an Iterable which is not a Collection.
The blog ate my generics! Let’s try again (underscore used for spacing):
for (Iteratorgt;g it = elements.iterator(); it.hasNext();) {
____if (ConditionIsSatisfied(e) ) {
________it.remove();
____}
}
I hate Luis Miranda.. always stealing my comments :-p
Using .NET 3.5 Linq
List ints =new List(new int[]{ 1,2,3,4,5,6,7});
ints = ints.Where((i) => (i % 2 == 0)).ToList();
By the way, how can i access a collection by index (just like i would in an array)?
I use some APIs that return collections and i really just need the first element.
I typically end up doing a iteration and breaking on the first result (which is pretty lame).
Thanks,
Luís
@João Craveiro: Yes you’re right. It can be heavier, but is very elegant
@Luís Miranda: that is an interesting solution. i’m going to explore it better. It’s very practical.
@Bruno Silva: Link, that is a thing i have to study. Thanks for your contribution.
@Luís Miguel Silva: Which collection are you thinking of? Almost all the containers in C# access the index the same way has in an array., for instance, has the index ([]) operator.
A List
Hello Nuno!
Take this example:
//get Fixed disk stats
System.Management.ObjectQuery oQuery = new System.Management.ObjectQuery(”select FreePhysicalMemory from Win32_OperatingSystem”);
ManagementObjectSearcher oSearcher = new ManagementObjectSearcher(oMs, oQuery);
ManagementObjectCollection oReturnCollection = oSearcher.Get();
// Hmm…how do i access a single element? :oP Oh well..
foreach (ManagementObject oReturn in oReturnCollection)
{
fm = Convert.ToInt32(Convert.ToInt32(oReturn["FreePhysicalMemory"]) / mb);
break;
}
return fm;
How can i access a single element from the returned ManagementObjectCollection ?
Thanks,
Luís Silva
I think i just found a method to do what i want: ManagementObjectCollection.CopyTo()
Any alternatives / thoughts?
Thanks,
Luís
Well, the object ManagementObjectCollection is really strange… They, at least, could have implemented an indexer.
And, as far as i found out, you’re not the only with this problem: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94753
If it was i implementing that code i would do the same has you did. Is the simpler solution because, as far as i could found out, there is no better one.
Even the CopyTo implies the creation of a container. I think it doesn’t worth the effort.
Dratz :o\
This isn’t the first object i’ve had this exact same problem!
It’s really a performance hog…
Thanks anyway!
Luís