Reputation: 14684
i want to know what is the best way to delete elements from a List in c# while doing a foreach.
here is a code sample. first i create a list with some elements and then delte one:
List<int> foo = new List<int>();
foo.Add(1);
foo.Add(2);
foo.Add(3);
foreach (int i in foo)
{
if (i==2)
{
foo.Remove(i);
}
}
when i run this, i get a InvalidOperationException
but how to solve this with a performant way?
Upvotes: 0
Views: 411
Reputation: 4350
You can't edit a list while you're iterating it.
Consider:
List<int> foo;
int[] bar = foo.ToArray();
foreach(int i in bar)
{
if (i == 2)
{
foo.Remove(i);
}
}
But beware: you should walk this list backwards, because removing an item from the foo list will mean the bar list no longer aligns with it. (If you don't walk backwards, you'll have to keep track of the count of removals and adjust the index passed to the remove call!)
Upvotes: 0
Reputation: 1479
foo.RemoveAll(x => x == 2);
In case you decide not to use for and foreach ;)
Upvotes: 9
Reputation: 17314
If you want to remove arbitrary elements, and not just one, you can use RemoveAll
and specify a predicate:
foo.RemoveAll(element => (element == 2));
Upvotes: 1
Reputation: 126804
I assume your actual use case is more complicated than what you have laid out. So let's assume you actually have some condition at play that applies to each element and that multiple elements can satisfy. We'll call that a predicate.
List<T>
exposes a RemoveAll
method that allows you to supply a predicate. Any item that matches that predicate is then removed. For example
Func<int, bool> isEven = i => i % 2 == 0;
List<int> ints = ...
ints.RemoveAll(item => isEven(item));
// ints will only contain odd numbers
Other approaches to consider would be walking over the list backwards in a for
loop and removing by index, building a second list containing the items to delete, and then in a second loop over the second list, remove items from the first. Or you could just write a query to construct a new sequence containing the items that you wish to keep.
Upvotes: 7
Reputation: 18349
I think the best way is to iterate backwards using a simple for
loop.
for(int i = foo.Count-1; i>=0; i--)
if(foo[i]==2) foo.RemoveAt(i);
Upvotes: 2
Reputation: 700222
You can add the items that you want to remove to a temporary list, then remove them after the loop:
List<int> foo = new List<int>();
foo.Add(1);
foo.Add(2);
foo.Add(3);
List<int> remove = new List<int>();
foreach (int i in foo) {
if (i==2) {
remove.Add(i);
}
}
foreach (int i in remove) {
foo.Remove(i);
}
Upvotes: 0
Reputation: 726489
If you must remove entries while enumerating, walk the list in backward direction, and remove items that you need to remove.
for (var i = foo.Count-1 ; i >= 0 ; i--) {
if (MustBeRemoved(foo[i])) {
foo.RemoveAt(i);
}
}
Note that this is not required in case of your post, where you know the values that need to be removed.
Upvotes: 12