See the following code:
List
for (int i = 1; i < 10; i++) { list.Add(i); } foreach (int i in list) { list.Remove(i); } [/source] Do you see anything wrong in this piece of code? No? Okay. Execute this code and you will get a System.InvalidOperationException with the message “Collection was modified; enumeration operation may not execute.”
The first time foreach loop executes, it deletes the first item and in the second iteration, this nasty exception is thrown. Reason? You deleted the first item and the list has changed. If not for the InvalidOperationException , you could have got a IndexOutOfRange exception while traversing the list.
So, how does one delete some items in the list while iterating through the list? I faced this problem in my project today and I couldn’t come up with an elegant solution. I did come up with a hack. I identify all items that need to be deleted and mark them with a flag (I need one iteration here). In another iteration, I create a new list and copy all those items which are not marked.
Sorry, I couldn’t come up with something better. If you have a solution or a better fix, please do let me know. Please note that if I want to remove all items, I can use list.Clear(). I am talking about a scenario where I want to delete only a select few items.
Update:
I read somewhere that if you use for loop instead of foreach, this problem does not arise. True, you will not get an exception, but you might not delete the items that you actually want to delete. Let’s see what happens in our case.
List
for (int i = 1; i < 10; i++)
{
list.Add(i);
}
for (int i = 0; i < list.Count; i++)
{
int remove = list[i];
list.Remove(remove);
}
[/source]
You will delete items 1, 3, 5, 7 and 9. After the for loop exits, your list will still have 2, 4, 6 and 8. Surprised?
Let's see why this is so.
First iteration: i = 0, remove = 1. Deleted item = 1 Once you delete this item, the list has changed. So, the first element in the list is now 2.
Second iteration: i = 1, remove = 3. Deleted item = 3
Third iteration: i = 2, remove = 5. Deleted item = 5
and so on….
So, replacing foreach with a for is not a solution.
Can you not use the ‘for’ method but loop backwards over the list removing them one at a time?
This should overcome the elements shifting into the position of those deleted.
Thanks for the solution, Tony.
See another solution here: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2314310&SiteID=1
That’s what I do.
for(int i=10 ; i>0 ; i–)
Remove(i);
For most cases like this, you can use delegates:
//removes all even numbers from list:
NumberList.RemoveAll(delegate(int x) { return x%2 == 0; });
Reverse-iteration is, traditionally, the “proper” way to do a For-loop that removes elements from the list.
Personally, though, I tend to just use delegates, if you’re lucky enough to be using the List class.
What I end up doing is making a copy of the list, removing the needed items from the copy, and then replacing the original with the copy to avoid this problem.
You can also just delete entry 0 (zero) in the for loop instead of deleting the i entry. Each time you look and remove index=0, you will create a “new” zero entry. You could of course set the count to zero…
gjunky, this works if I want to delete all the items in the list. What if I want to delete some items depending on some condition?
I use the more elegant “black list”:
List remList = new List();
foreach (TestClass tc in list)
if (hasToBeDeleted) remList.Add(tc);
list.RemoveAll(new Predicate(delegate(TestClass x) { return remList.Contains(x);}));
it is anything but not elegant…
I use a different approach, create a second list that “filtter” the items that must be removed and then replace the original list with the new one.
Basically is like “filtering” instead of “removing”, the cons is that you must recreate the list but I think the Add operation for List must not be so heavy.
Here is an example (observe the ! preceding the condition that indicates which items must be removed, it is negative logic!):
//Orignal List
List list = new List();
for (int i = 1; i < 10; i++)
{
list.Add(i);
}
//Filtered List
List newList = new List();
foreach (int i in list)
{
if (! MustRemove(i))
newList.Add(i);
}
//Replacing the original list
list = newList;
Regards.
I like this gentleman’s approach; wrap it up ina isloator class that lets you modify the items of the list while iterating it:
http://www.koders.com/csharp/fidF2C8E1786AE76101911914CCA9286E25B398AED6.aspx
What I do is, during the first iteration, I get the lndexes of elements that i want to remove and then call the following function :
private void removeElementsFromList(List list, List indexOfElementsToBeRemoved)
{
try
{
Collections.sort(indexOfElementsToBeRemoved);
Iterator indexes = indexOfElementsToBeRemoved.iterator();
int counter = 0;
while(indexes.hasNext())
{
int updatedIndexOfItemToBeRemoved = indexes.next() – counter;
list.remove(updatedIndexOfItemToBeRemoved);
counter++;
}
}
catch (Exception e)
{
}
}
I have a recommendation. Borrowing from the other site in question, I recommend this approach:
int t = 0;
object o;
while ( t < list.count )
{
o = list[t];
if ( o.shouldDelete() )
list.remove(o);
else
t++;
}
You’ll either run out of elements or get to the end of the list.
your code aint correct, just check if you have a list with four elements, in the case that all elements must be removed you will have:
1st iteration:
t = 0 § Count = 4
t = 1 § Count = 3
t = 2 § Count = 2 => You’re able to remove only half of the total quantity you were supposed to remove ..
Actually, the code is corret… you aint.
t is not getting incremented when an item is removed. Removing all is:
Count = 4, t = 0 -> Count = 3, t = 0 -> Count = 2, t = 0 -> Count = 1, t = 0 -> Count = 0.
All 4 elements are removed.
int i = 0;
while (i < list.Count)
{
if (ShouldRemove(list[i]))
list.RemoveAt(i);
else
i++;
}
maybe list.Clear();
?
Maybe read the blog post?
Using the for solution, only increment if you didn’t remove.
I think Josh’s solution using a delegate is the most elegant. However, if delegates are not an option, why not iterate over a copy of the original list? That way you’d come up with something looking pretty close to what you originally wanted to do …
foreach (int i in new List(list))
{
list.Remove(i);
}
Far more readable than the “black list” approaches above IMHO and you can avoid having to manually maintain a list index until you really need to for performance reasons.
Oops, the generic list declaration was stripped by WordPress … I’ll try again 🙂
foreach (int i in new List<int>(list))
{
list.Remove(i);
}
It’s easier than that. This works for both foreach and for loops.
// Create 2 lists.
new List
new ListDeletions
// Iterate through the loop
For each item in list
if condition is met add this to listDeletions
// When the loop is finished update List
List.Except(ListDeletions)
It’s called Linq and it works for removing any specific entries in any order
What you guys are talking about is a FIFO list aka. Queue. You could do like a previous comment said. Create a for loop and loop through the entries in reverse order removing the items after they have been processed. The downside of this is is creates a LIFO list aka. stack. So, to reverse it, you’d have to duplicate the original list in the reverse order to actually create a queue.
I can vouch that both these methods work because I have used both. If you use the for Stack it is more performant but less flexible.
There are also specific classes that are tied into iEnumerable. Called Stack and Queue (go figure).
You can find specifics on how to use queue here:
http://www.blackwasp.co.uk/Queue.aspx
And how to use the stack here:
http://www.blackwasp.co.uk/Stack.aspx
There’s also a Freemind MindMap for C# Here:
freemind.sourceforge.net/wiki/extensions/freemind/flashwindow.php?startCollapsedToLevel=3&initLoadFile=/wiki/images/e/ee/CSharp_2_WebLinks2.mm&mm_title=C%23%202.0%20Computer%20Language%20-%20Contents
You can find it in the MindMap under C# 2.0 Collections
There’s no need to re-invent the wheel, unless you need a custom implementation that performs better.
If you work with iEnumerables a lot I suggest you learn Linq-To-Objects, it will save you an untold amount of dev time. Check out [2008 – Apress – LINQ For Visual C Sharp 2008. It’s the only decent book resource I’ve found on the subject so far.
A++++++++++
This is the best way!
I have a List of session items and a user created subset of items (via checkboxes of the original list).
After an action occurs on the subset I need to remove them from the session list before rebinding to the datalist.
This is PERFECT!
delegates are definately the best approach and now you have the benefit of lamda expressions which are even more concise and elegant.
what about for dictionary?
you can’t normal for() loop over it, apparently
thanks for the delegate code here… ive never used it befre and i just did! I am writing a game in C# and XNA and keeping track of bullets fired and managed by my ObjectManager class. This allows me to delete ‘dead’ projectiles instead of reusing them- thanks for the idea!
The issue I had was editing an object in the list, and possibly removing it on a condition. Not sure if a delegate would work. I did as follows:
List MyList;
ObjClass [] temp = new ObjClass[MyList.Count];
ObjClass.CopyTo(temp);
foreach (ObjClass obj in temp)
{
//if condition met, modifiy obj properties
obj.x = … obj.y = …
//if other condition met, remove obj
MyList.Remove(obj);
}
It is as easy as unbinding the list from foreach. Just add ToArray() to the list
List list = new List();
for (int i = 1; i < 10; i++)
{
list.Add(i);
}
foreach (int i in list.ToArray())
{
list.Remove(i);
}
Yup this works… It’s like Splice implementation, which perhaps resets the Enumerators….
The reverse for loop is the fastest method:
for (int idx = list.Count – 1; idx >= 0; idx–)
{
if (list[idx].Remove()) list.RemoveAt(idx);
}
1) The Count property is called only once. In a foward loop it would be called after each iteration, or you would have to assign it to a variable before hand.
2) RemoveAt() has better performance than Remove().
3) Though I wouldn’t know for sure, my instinct is that ForEach is slower that For.
4) Obviously solutions that copy lists to other lists, will be adding all sorts of weight to the procedure. And though it doesn’t appear to be the case, methods like list.ToArray() are doing just that.
It’s not that ugly in my opinion.
To remove selected item in multiselect list box:
for (int i=lbx_ProdMaster.Items.Count ; i>0 ; i–)
{
if(lbx_ProdMaster.Items[i-1].Selected == true)
{
lbx_ProdMaster.Items.RemoveAt(i-1);
}
}
You can use lambda expressions as shown here
http://my6solutions.com/post/2009/07/13/Collection-was-modified3b-enumeration-operation-may-not-execute.aspx
This annoys me to no end.
The proper (imho) way to do this is to use a LinkedList (either use the default one or roll your own). This kind of dynamic modification is what linked structures were designed for.
However, there really SHOULD be a higher level abstraction for doing this kind of enumeration.
The “for each” syntax is very elegant to use, but its associated semantics are too restrictive. I think it should work the same way a linked list works, which is that you can make any modifications you want to the list while enumerating, and there’s always a fixed marker for where you currently are in the list, whose absolute position may change with the changes made to the list.
That way, there would be no indexing errors, although you wouldn’t be able to guarantee that the “for each” would ever terminate (i.e. might get an infinite loop). But this is a lesser evil.
The best solution could be using While loop.
While (list it not empty)
{
Delete First item
}
this will not give exception at all.
Jayvardhan Patil
http://codeforfuture.com
The reverse iteration is just what I needed. I would’ve never thought of trying that. Thanks!
Holy cow, it’s is just appalling to see so many solutions that reek of disregard to runtime efficiency! Josh has posted a clean and solution. All solutions that include copying, converting to arrays etc are almost as bad as the sort of solutions that PHP and BASIC coders come up with.
When there are methods already present in the .NET library, *use them*. Just like Josh does. That’s what they’re there for.
All solutions that manually grind though the list with for or while loops are “procedurally oriented”. You should just use the RemoveAll method provided in the List class.
Example:
playerShots is a list of Shot objects for a game. Location is a Point that is a property of a Shot. The following code removes all shots from the playerShots list that have reached the top of the screen…
playerShots.RemoveAll(delegate(Shot s)
{
return s.Location.Y < 0;
});
Let C# work for you.
Yep, Josh is right.
foreach (ClientHandler client in clientList.Reverse())
{
if (client.IsDone())
{
clientList.Remove(client);
}
}
Good day guys, Josh’s solution worked for me, but I am having a hard time understanding the concept behind delegates. Can anyone give a simple explanation behind it? Thanks.
Why don’t you do it like this?
for(int i = 0; i < mylist.Count; i++)
{
if(mycondition)
{
mylist.Remove(mylist[i–]);
}
}
Every time you remove sth from mylist the property Count will be decreased and i too.
The var i will point on the element right after the deleted one. So nothing will be skipped….
Right?
I used this to remove image locations from a list:
for (int j = 0; j < imageLocation.Count; j++)
{
imageLocation.RemoveAt(0);
j–;
}
You are an idiot. When deleting items like
08 for (int i = 0; i 0)
{
list.RemoveAt(0);
}
don’t forget to decrement i. The easiest way is to use ‘while’ loop while Count > 0
public static class Extensions
{
public static IEnumerable Mutable(this List list)
{
int counter = 0;
int size = list.Count;
while (counter < size)
{
if (list.Count != size)
{
counter -= size – list.Count;
size = list.Count;
}
yield return list[counter++];
}
}
}
List list = new List();
list.Add(null);
list.Add(null);
list.Add(null);
foreach (object one in list.Mutable())
{
list.Remove(one);
}
No error..
Attempts to modify the index as if you deleted from the current position or less.
Maybe a little dangerous though!
Try this less code:
Use the class System.Collections.IEnumerator
IEnumerator iterator = list.GetEnumerator();
do
{
//In here you could some kind of check
//For which items you want to remove list.Remove(iterator.Current);
} while (iterator.MoveNext());
nevermind.. thought that would work iterator works that way in java
Same problem
You can also do something like this:
list.Where().ToList().Foreach(item => list.Remove(item));
List list = new ArrayList();
Student s = null;
for(int i=0;i<10;i++) {
s = new Student();
s.setName("name-"+i);
list.add(s);
}
System.out.println(list);
for(int i=0;i<list.size();i++) {
if(list.get(i).getName().equals("name-3") || list.get(i).getName().equals("name-4") || list.get(i).getName().equals("name-7") || list.get(i).getName().equals("name-0") || list.get(i).getName().equals("name-2") || list.get(i).getName().equals("name-1") || list.get(i).getName().equals("name-9")) {
list.remove(i);
i–;
}
}
System.out.println(list);
Or now you can call RemoveAll() using a predicate for your particular case.
Thank you for this post, it helped me I faced the same issue. I first tried the delegate solution:
Shapes.RemoveAll(delegate(Shape shapeToDelete) { return shapeToDelete.Count shapeToDelete.Count < MinimalShapePixels);
Pretty cool 🙂
iList.dataList.RemoveAll(delegate(Data x){return (x.dataIndex == m || x.dataIndex == n);});
m and n are the index of iList those I wanted to delete. Thanks for this great post
dataIndex is a custom property of custom structure Data which forms a custom List in dataList
I would typically use a reverse for loop, but if you have to traverse the list in the original order, then just make a small change to the incrementing:
for( int i = 0; i < list.Count; i ++ )
{
if( list[i].shouldBeRemoved() )
{
list.RemoveAt(i–);
}
}
why don’t you just try this if you’re wanting to delete an item?
int i = 0;
while (i != list.Count) {
if ( list[i] fits the condition to be deleted ) {
list.erase(i);
}
else {
i++;
}
}
Why not keep it simple?
fooBar.RemoveAll(o => o.foo == bar);
Wow, Deleting backwords is an excellent solution ! 😀
wow 4 years old and still looking for newer wheels
[…] had me stumped for a good 5 min until I found the following post by a guy having a similar issue “https://generally.wordpress.com/2007/10/24/removing-items-in-a-list-while-iterating-through-it/”, this did not solve the issue but a comment in it […]
I found the easiest thing to do is add a subtraction within the loop…
here i am iterating through a list removing everything…
for (int i = 0; i < modules.Count; i++)
{
modules[0].Close();
i–;
}
why not remove with this?
for (int i = 0; i < list.Count; i++)
{
int remove = list[i]; //this assigns list[0] to remove
list.Remove(remove); //this deletes list[0]
i–; //this makes sure the next element will be the next element 😉
}
or even simplier!
for (int i = 0; i < list.Count; i++)
{
list.Remove(list[i]); //this deletes list[0]
i–; //this makes sure the next element will be the next element
}
But everytime you remove an item from the list you can do I– operation.
Thanks the ToList() posted in the comments fixed this for me:
returnValue.ToList().ForEach(delegate(Item item) {
if (item.Active)
returnValue.Remove(item);
});
The problem I had before was not using ToList() and it was resizing the original list.
Just add a i–; each time you remove something …
Actually “for” is very straightforward:
for (int i = 0; i = 0; –i )
{
if( shouldRemove( list[ i ] ) )
{
list.Remove( i );
}
}
I figured out how to do this recursively, should be fine for short lists.
List intList = new List ();
// add some items
RecursiveDelete(0);
public void RecursiveDelete(int index)
{
// check for end point
if (index == intList.Count) return;
// Get this value (happens before any deletes)
int v = intList[index];
// Recurse
RecursiveDelete(index + 1);
// Possibly delete this value
if (condition) intList.Remove(v);
}
‘How about this? Pretty short, clean and straight forward.
For i = 0 To lst.Count – 1
If bolYourCondition Then
lst.RemoveAt(i- iRemoveCnt) ‘Remove
iRemoveCnt += 1
End If
Next
And if you have a forward looping for structure already there is not need to change it.
Create a new list:
var newList = myList.ToList();
foreach(var item in newList) myList.Remove(item);
not one curly!
“Removing items in a list while iterating through it | Codelicious” was indeed a fantastic posting.
If merely there was more weblogs like this amazing one on the
net. Well, many thanks for ur precious time, Lolita
[…] had me stumped for a good 5 min until I found the following post by a guy having a similar issue “https://generally.wordpress.com/2007/10/24/removing-items-in-a-list-while-iterating-through-it/”, this did not solve the issue but a comment in it did.Here is my complete […]
Panic attacks are serious and can make a person feel like they
are out of control, having a heart attack, or like they cannot
breathe. All this is to help set up your body and mind to be faster, stronger and more alert, i.
After my senior year and graduating, barely, I was on my own to face the world.
I use a doubly linked list for situations like this.
var n = list.first;
while(n != null){
// add or remove here
n = n.next;
}
If you remove an item, ‘n.next’ points to the next node. If you add an element, it tacks it onto the end of the list. For iteration or adding and removing while iterating, a doubly linked list is awesome. However, if you want to look up elements based on an index, it can be slow if you don’t implement your own lookup system…
For example a separate hash with indexes pointing directly to nodes within the list.
[…] had me stumped for a good 5 min until I found the following post by a guy having a similar issue “https://generally.wordpress.com/2007/10/24/removing-items-in-a-list-while-iterating-through-it/”, this did not solve the issue but a comment in it did.Here is my complete […]
Great blog. Thank you for sharing.