CodeGym /Courses /C# SELF /Removing an Element from a Collection in a

Removing an Element from a Collection in a foreach Loop

C# SELF
Level 29, Lesson 4
Available

1. Introduction

Pretty much everyone who starts coding in C# runs into the same problem sooner or later: you have a collection (like a list of objects), and you need to remove some unwanted elements based on a condition. Sounds simple, and your hand just reaches for the familiar, comfy foreach loop, since it's the “safest” and “friendliest” way to go through stuff. But suddenly, out of nowhere, you get a mysterious runtime error that never showed up in simple examples — and your program just stops dead in its tracks.

Let's figure out why this happens, what's going on “under the hood” with collections and iterators, and how to remove elements the right way so you don't get any surprises or bugs.

Why foreach Doesn't Play Nice with Removing Elements

To really get what's happening, imagine a line of people (that's our collection). You're walking down the line, asking each person: "Should I keep you or cross you out?" If you start crossing people out right while you're going through the line, the whole line shifts, people move around, and your plan of “next person — next in line” falls apart instantly. Someone might not get asked, or you might ask someone twice.

Example in C#:


List<string> names = new List<string> { "Anton", "Boris", "Vika", "Grisha" };

foreach (string name in names)
{
    if (name.StartsWith("V"))
        names.Remove(name); // Boom! InvalidOperationException
}

When the program gets to "Vika" and tries to remove her, the internal iterator loses “touch with reality” — and you'll get this message:
InvalidOperationException: Collection was modified; enumeration operation may not execute.

This isn't just some random rule — C# is protecting you from sneaky bugs and broken data structures.

2. Why Doesn't Such a Simple Code Work?

So, How Does It Work Inside?

When you write a foreach loop, the compiler generates a special object — an iterator (IEnumerator) that keeps track of where you are in the collection. This object remembers how many elements there were at the start, which element is “active” now, and strictly checks that the collection doesn't change while you're looping through it.

Any attempt to remove or add an element inside foreach breaks this contract. Why? If you remove elements and the indexes shift, the iterator can't move to the next element correctly. Someone might get skipped, someone might get counted twice — total mess. So, at the very first change, .NET honestly and clearly throws an error.

What Happens If You Remove "Head-On"

Let's say you wrote this program:


List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
foreach (int x in numbers)
{
    if (x % 2 == 0)
        numbers.Remove(x);
}

Seems logical: go through all the numbers, remove the even ones. But on the second pass, the program throws an error — “collection was modified during enumeration.”

Sometimes you might want to ignore this warning and try it “at your own risk.” But even if there was no error, depending on the collection's structure, the result would be unpredictable. For example, you might accidentally “jump over” some elements or not remove everything you wanted.

3. So, What's the Right Way?

Technique #1: Reverse for Loop

The thing is, when you remove an element, all the next elements shift left, and if you go from the start of the list, it's easy to mess up the indexes and skip stuff. To avoid this, it's smart to go from the end.


List<string> names = new List<string> { "Anton", "Boris", "Vika", "Grisha" };

for (int i = names.Count - 1; i >= 0; i--)
{
    if (names[i].StartsWith("V"))
        names.RemoveAt(i);
}

In this example, after each removal, all elements after the removed one shift, but the indexes you haven't processed yet are safe. So nothing gets skipped.

Technique #2: Filter and Create a New List

Sometimes it's easier (and often faster) to go through the collection, grab only the elements you want to keep, and replace the original list with the new one.


var names = new List<string> { "Anton", "Boris", "Vika", "Grisha" };
names = names.Where(name => !name.StartsWith("V")).ToList();
// In the end, you'll have "Anton" and "Grisha"

This approach is good when the collection isn't too big or you don't care about keeping the original object reference.

Technique #3: Use Special Collection Methods

If you're working with a classic List<T>, there's a handy method for removing by condition:


names.RemoveAll(name => name.StartsWith("V"));

Everything inside will be handled right, and you get short and clear code.

Technique #4: Collect for Removal

Some collections can't be changed “on the fly” (like Dictionary, HashSet, or even your own class). In these cases, use the “mark for removal” approach:

  1. First, go through the collection and collect all the elements you want to remove into a separate list.
  2. Then, go through this new list and remove the needed elements from the original collection.

Dictionary<int, string> dict = new Dictionary<int, string> { [1] = "one", [2] = "two", [3] = "three" };
var toDelete = new List<int>();
foreach (var kvp in dict)
{
    if (kvp.Key % 2 == 0)
        toDelete.Add(kvp.Key);
}
foreach (var key in toDelete)
    dict.Remove(key);

4. Handy Nuances

Beginner Mistakes and Myths

One of the most common mistakes is expecting that removing an element from a collection while looping will work 'somehow', since in some other languages (like Python) it's often possible. But in C# this is strictly forbidden for your own safety: it's way better to get a clear error than a sneaky, nasty bug that nobody can ever reproduce.

Another common mistake is using a for loop with increasing index instead of decreasing. This makes it so that after removing an element, all the next ones “shift”, and some elements will get skipped. Always go from the end to the start if you're removing by index.

The Moral of the Story

The task “remove elements from a collection by condition” pops up in every other C# program, but doing it right inside a foreach loop is a no-go — that's just how the language is built, to keep your data safe and avoid unexpected errors.
Remember this rule, and it'll save you from sleepless nights with the debugger.

How to Always Do It Right

  • Never remove elements from a collection right inside a foreach loop. It'll throw a runtime error.
  • For lists (List<T>) and arrays, use either a for loop from the end, or the RemoveAll method and LINQ filtering.
  • For dictionaries, sets, and other complex collections — first collect the elements to remove, then go through that list and remove them from the original collection.
  • If you're not sure — think: how does the collection change when you remove something? What will the iterator do? If you have even a tiny doubt, your method is probably wrong.
2
Task
C# SELF, level 29, lesson 4
Locked
Removing strings that start with a given character
Removing strings that start with a given character
1
Survey/quiz
Filtering Elements, level 29, lesson 4
Unavailable
Filtering Elements
Working with Collections
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION