Remove elements from a list while iterating over it in C#
This post will discuss how to remove elements from a list in C# that satisfies the given condition while iterating over it.
Problem: We can’t iterate over a list and simply remove elements from it.
Reason: Moving forward in the list using a for-loop and removing elements from it might cause you to skip a few elements. In other words, when the i’th element of the list is removed, the element positioned at the next index becomes the new i’th element. Now in the next iteration of the for-loop, since index i gets incremented, the unprocessed i’th element will be skipped.
This is evident from the following example where the expected output should be empty, but the actual output is [2,4,6,8,10].
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using System; using System.Collections.Generic; using System.Linq; public class Example { public static void Main() { List<int> list = new List<int>(Enumerable.Range(1, 10)); for (int i = 0; i < list.Count; i++) { list.RemoveAt(i); } Console.WriteLine(String.Join(',', list)); } } |
Also, InvalidOperationException will be thrown if we try to move forward in the list using the foreach loop and remove elements from it. This exception is thrown when a method call is invalid for the object’s current state.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
using System; using System.Collections.Generic; using System.Linq; public class Example { public static void Main() { List<int> list = new List<int>(Enumerable.Range(1, 10)); foreach (int item in list) { list.Remove(item); // throws `InvalidOperationException` } Console.WriteLine(String.Join(',', list)); } } |
There are several workarounds to solve the above problems:
1. Iterate Backwards
An elegant solution is to iterate backward in the list, which does not skip anything, and we can call the RemoveAt() method for removing elements.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System; using System.Collections.Generic; using System.Linq; public class Example { public static void Main() { List<int> list = new List<int>(Enumerable.Range(1, 10)); for (int i = list.Count - 1; i >= 0; i--) { if (list[i] % 2 == 0) { // remove even elements list.RemoveAt(i); } } Console.WriteLine(String.Join(',', list)); } } /* Output: 1,3,5,7,9 */ |
2. Using List<T>.Reverse() method
Another solution to get around the above problem is to iterate over a reversed copy of the list using the foreach loop. The following code example shows how to implement this using LINQ’s Reverse() method:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System; using System.Collections.Generic; using System.Linq; public class Example { public static void Main() { List<int> list = new List<int>(Enumerable.Range(1, 10)); foreach (int item in list.Reverse<int>()) { if (item % 2 == 0) { // remove even elements list.Remove(item); } } Console.WriteLine(String.Join(',', list)); } } /* Output: 1,3,5,7,9 */ |
3. Decremeting index
We can also decrement index i in the loop when the i'th element is removed from the list. Now, the i'th element will not be skipped.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
using System; using System.Collections.Generic; using System.Linq; public class Example { public static void Main() { List<int> list = new List<int>(Enumerable.Range(1, 10)); for (int i = 0; i < list.Count; i++) { if (list[i] % 2 == 0) { // remove even elements list.RemoveAt(i--); } } Console.WriteLine(String.Join(',', list)); } } /* Output: 1,3,5,7,9 */ |
4. Use Another Collection
Instead of removing elements as moving forward in the list, we create a collection of such elements and delete them later. Depending upon the deletion condition used, this approach might fail if the list contains duplicate elements.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
using System; using System.Collections.Generic; using System.Linq; public class Example { public static void Main() { List<int> list = new List<int>(Enumerable.Range(1, 10)); HashSet<int> toRemove = new HashSet<int>(); foreach (int item in list) { if (item % 2 == 0) { // remove even elements toRemove.Add(item); } } list.RemoveAll(toRemove.Contains); Console.WriteLine(String.Join(',', list)); } } /* Output: 1,3,5,7,9 */ |
That’s all about removing elements from a list while iterating over it in C#.
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)