C# List - Removing items while looping / iterating

C#.NetListCollections

C# Problem Overview


Suppose that I have the following code snippet:

var data=new List<string>(){"One","Two","Three"};
for(int i=0 ; i<data.Count ; i++){
  if(data[i]=="One"){
    data.RemoveAt(i);
  }
}

The following code throws exception.

My question is what is the best way to avoid this exception and to remove the element while looping?

C# Solutions


Solution 1 - C#

If you need to remove elements then you must iterate backwards so you can remove elements from the end of the list:

var data=new List<string>(){"One","Two","Three"};
for(int i=data.Count - 1; i > -1; i--)
{
    if(data[i]=="One")
    {
        data.RemoveAt(i);
    }
}

However, there are more efficient ways to do this with LINQ (as indicated by the other answers).

Solution 2 - C#

You can use List<T>.RemoveAll to handle this:

data.RemoveAll(elem => elem == "One");

Solution 3 - C#

You can also use a forward moving loop like:

var data = new List<string>() { "One", "Two", "Three", "One", "One", "Four" };
for (int i = 0; i < data.Count; i++)
{
    if (data[i] == "One")
    {
        data.RemoveAt(i--);
    }
}

This line data.RemoveAt(i--); is stopping the effect of increment in the iteration variable at the end of the loop, in case of item being removed from the list.

It will remove the item from index at the current iteration value and then after removing the item, the iterator would be set to one less value than the current one. At the end of loop, the increment in loop body will move it to next valid index.

Here is a working dotfiddle

(Please note, that I personally use reverse loop for situation like these because IMO, they are easier to understand, this answer here is just for displaying another way of achieving it).

Solution 4 - C#

I happen to come across a simple solution for this using foreach and .ToArray()

  var data=new List<string>(){"One","Two","Three"};
   foreach ( var d in data.ToArray()){
      if(d =="One"){
        data.Remove(d);
      }
    }

Solution 5 - C#

You could try ChrisF's reverse iteration method to remove your item.

You could also simply:

List.Remove("One");

Or:

List.RemoveAll(i => i == "One"); // removes all instances

And be done with it. There's really no point in iterating over the collection to remove a single item.

Solution 6 - C#

Why don't you just simply decrement the iterator variable?

var data=new List<string>(){"One","Two","Three"};
for(int i=0 ; i<data.Count ; i++){
  if(data[i]=="One"){
    data.RemoveAt(i);
    i--; // <<<<<<<<<<<
  }
}

Solution 7 - C#

Here is a dirty trick and I wonder what the critique of it will be?

var data=new List<string>(){"One","Two","Three"};
foreach (string itm in (data.ToArray()))
{
  if string.Compare(name, "one", true) == 0) data.Remove(name);
}

Solution 8 - C#

var data=new List<string>(){"One","Two","Three"};
for(int i=0; i<data.Count; ){
  if(data[i]=="One") data.RemoveAt(i);
  else ++i;
}

Solution 9 - C#

The general solution below makes a copy of the list and handles the negative index:

foreach (void item_loopVariable in MyList.ToList) {
	item = item_loopVariable;

}

Solution 10 - C#

        var data = new List<string>() { "One", "Two", "Three" };
        data.RemoveAll(p=>p=="One");

Solution 11 - C#

You can use Stack class

        Stack<string> myStack = new Stack<string>();

        foreach (var item in Enumerable.Range(1,1001))
            myStack.Push("Str " + item.ToString());

        while (myStack.Any())
            Console.WriteLine("Now {0} items in Stack, removed item is {1}",myStack.Count,myStack.Pop());

        Console.ReadKey();

Solution 12 - C#

I had to remove more than one item from the list. so,I reinitialized the list count. Is there any other better option?

for (int i = dtList.Count - 1; dtList.Count > 0; )
{
     DateTime tempDate = dtList[i].Item1.Date;
     var selectDates = dtList.FindAll(x => x.Item1.Date == tempDate.Date);
     selectDates.Sort((a, b) => a.Item1.CompareTo(b.Item1));
     dtFilteredList.Add(Tuple.Create(selectDates[0].Item1, selectDates[0].Item2));
     dtList.RemoveAll(x => x.Item1.Date == tempDate.Date);
     i = dtList.Count - 1;
}

Solution 13 - C#

List<string> list = new List<string>();
     list.Add("sasa");
     list.Add("sames");
     list.Add("samu");
     list.Add("james");
     for (int i = list.Count - 1; i >= 0; i--)
     {

         list.RemoveAt(i);

    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAshraf Sayied-AhmadView Question on Stackoverflow
Solution 1 - C#ChrisFView Answer on Stackoverflow
Solution 2 - C#Reed CopseyView Answer on Stackoverflow
Solution 3 - C#HabibView Answer on Stackoverflow
Solution 4 - C#PushpendraView Answer on Stackoverflow
Solution 5 - C#Justin NiessnerView Answer on Stackoverflow
Solution 6 - C#PewpewView Answer on Stackoverflow
Solution 7 - C#B HView Answer on Stackoverflow
Solution 8 - C#TutankhamenView Answer on Stackoverflow
Solution 9 - C#alwaysVBNETView Answer on Stackoverflow
Solution 10 - C#Nivid DholakiaView Answer on Stackoverflow
Solution 11 - C#user2734846View Answer on Stackoverflow
Solution 12 - C#MadhuView Answer on Stackoverflow
Solution 13 - C#Sajidur RahmanView Answer on Stackoverflow