What happens if you’re iterating through a collection using a foreach() loop and you decide you want to delete an item? You’ll get the message “Collection was modified; enumeration operation may not execute.” While there are a variety of ways to solve this, there’s one quite elegant solution.
[The Elegant Uni...List]
A fellow denizen in the ##XNA channel on FreeNode had an inquiry involving a foreach() loop and deleting items.
The general idea is that you have a list of items, and some of those items you may want to delete out of the list as you’re traversing it. You can do this with multiple lists, using a queue where you requeue items, tagging what should be deleted, etc. But none of those are elegant.
So, let’s say you only want a single list, you don’t care about the order of the items in said list, and you want to iterate over it exactly once. For all the elements in the list: if you find one you want to delete then you swap it with the “last” element, recheck the current index, and decrease the total count of items in the list. Generically it would look like:
lastIndex <- list.Count
for index <- 0 to lastIndex
do if list[index] is to be deleted
then
swap(list[index], list[lastIndex])
index <- index - 1
lastIndex <- lastIndex - 1
list <- { list[0] .. list[lastIndex] }
Voilà.
[Sample Code]
Here’s an example that will check if elements in a List are even, and remove them. Note that the ending order won’t necessarily be the same as the starting order. Also, this system works for reference types.
using System;
using System.Collections.Generic;
namespace ListDelete
{
class Program
{
static void Main()
{
List<int> MyList = new List<int>() { 1, 2, 7, 3, 4, 4, 5, 5, 6, 7 };
int lastIndex = MyList.Count;
int index = 0;
for (index = 0; index < lastIndex; index++)
{
if (MyList[index] % 2 == 0)
{
// swap this element with the last element
var x = MyList[index];
MyList[index] = MyList[lastIndex-1];
MyList[lastIndex - 1] = x;
// recheck this index
--index;
// decrease our total number of elements to be worked on
--lastIndex;
} // if
} // for index
// remove the elements we no longer wanted
MyList.RemoveRange(index, MyList.Count - lastIndex);
// Display the remaining elements in the list
foreach (var item in MyList)
{
Console.WriteLine(item);
} // foreach
Console.WriteLine("Press any key to continue...");
Console.ReadKey(); // Wait for user input to exit
} // void Main()
} // class Program
} // namespace
The output of the above is:
1 7 7 3 5 5 Press any key to continue...

Recent Comments