C# List - Removing Items While Looping/Iterating

How to remove elements from a generic list while iterating over it?

Iterate your list in reverse with a for loop:

for (int i = safePendingList.Count - 1; i >= 0; i--)
{
// some code
// safePendingList.RemoveAt(i);
}

Example:

var list = new List<int>(Enumerable.Range(1, 10));
for (int i = list.Count - 1; i >= 0; i--)
{
if (list[i] > 5)
list.RemoveAt(i);
}
list.ForEach(i => Console.WriteLine(i));

Alternately, you can use the RemoveAll method with a predicate to test against:

safePendingList.RemoveAll(item => item.Value == someValue);

Here's a simplified example to demonstrate:

var list = new List<int>(Enumerable.Range(1, 10));
Console.WriteLine("Before:");
list.ForEach(i => Console.WriteLine(i));
list.RemoveAll(i => i > 5);
Console.WriteLine("After:");
list.ForEach(i => Console.WriteLine(i));

Remove an item in a list while it's in a foreach loop c#

Try just creating another temporary list for the items that need to be deleted then when your done looping you can just delete the ones in the temp list.

List<Type> temp = new List<Type>()
foreach(item in mainList)
{
if (item.Delete)
{
temp.Add(item);
}
}

foreach (var item in temp)
{
mainList.Remove(item);
}

C# List - Removing items while looping / iterating

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).

Best way to iterate over a list and remove items from it?

Willy-nilly you have to loop over the list, and the for loop is the most efficient one:

  for (int i = safePendingList.Count - 1; i >= 0; --i) 
if (condition)
safePendingList.RemoveAt(i);

If you want to remove in range (not in the entire list), just modify for loop:

  // No Enumarable.Range(1, 10) - put them into "for"
for (int i = Math.Min(11, safePendingList.Count - 1); i >= 1; --i)
if (condition)
safePendingList.RemoveAt(i);

Or if you have to remove items in forward looping:

  for (int i = 0; i < safePendingList.Count;) // notice ++i abscence
if (condition)
safePendingList.RemoveAt(i);
else
i += 1; // ++i should be here

On the contrary safePendingList.ToList() creates a copy of initial safePendingList and this means memory and CPU overhead:

  // safePendingList.ToList() - CPU and Memory overhead (copying)
foreach (var item in safePendingList.ToList()) {
if (condition)
myList.Remove(item); // Overhead: searching
}

However, the most reasonable plan in many cases is just to let .Net work for you:

  safePendingList.RemoveAll(item => condition);

Problems removing elements from a list when iterating through the list

When using List<T> the ToArray() method helps in this scenario vastly:

List<MyClass> items = new List<MyClass>();
foreach (MyClass item in items.ToArray())
{
if (/* condition */) items.Remove(item);
}

The alternative is to use a for loop instead of a foreach, but then you have to decrement the index variable whenever you remove an element i.e.

List<MyClass> items = new List<MyClass>();
for (int i = 0; i < items.Count; i++)
{
if (/* condition */)
{
items.RemoveAt(i);
i--;
}
}

Remove/Add items to/from a list while iterating it

Removing multiple elements from a list 1 by 1 is a C# anti-pattern due to how lists are implemented.

Of course, it can be done with a for loop (instead of foreach). Or it can be done by making a copy of the list. But here is why it should not be done. On a list of 100000 random integers, this takes 2500 ms on my machine:

       foreach (var x in listA.ToList())
if (x % 2 == 0)
listA.Remove(x);

and this takes 1250 ms:

        for (int i = 0; i < listA.Count; i++)
if (listA[i] % 2 == 0)
listA.RemoveAt(i--);

while these two take 5 and 2 ms respectively:

        listB = listB.Where(x => x % 2 != 0).ToList();

listB.RemoveAll(x => x % 2 == 0);

This is because when you remove an element from a list, you are actually deleting from an array, and this is O(N) time, as you need to shift each element after the deleted element one position to the left. On average, this will be N/2 elements.

Remove(element) also needs to find the element before removing it. So Remove(element) will actually always take N steps - elementindex steps to find the element, N - elementindex steps to remove it - in total, N steps.

RemoveAt(index) doesn't have to find the element, but it still has to shift the underlying array, so on average, a RemoveAt is N/2 steps.

The end result is O(N^2) complexity either way, as you're removing up to N elements.

Instead, you should use Linq, which will modify the entire list in O(N) time, or roll your own, but you should not use Remove (or RemoveAt) in a loop.

How add or remove object while iterating Collection in C#

foreach is designed for iterating over a collection without modifing it.

To remove items from a collection while iterating over it use a for loop from the end to the start of it.

for(int i = gems.Count - 1; i >=0 ; i--)
{
gems[i].Value.Update(gameTime);

if (gems[i].Value.BoundingCircle.Intersects(Player.BoundingRectangle))
{
Gem gem = gems[i];
gems.RemoveAt(i); // Assuming it's a List<Gem>
OnGemCollected(gem.Value, Player);
}
}

If it's a dictionary<string, Gem> for example, you could iterate like this:

foreach(string s in gems.Keys.ToList())
{
if(gems[s].BoundingCircle.Intersects(Player.BoundingRectangle))
{
gems.Remove(s);
}
}

c# Removing element while traversing list- iterate backwards or use i-- or using linq to iterate and remove at the same time?

The preferred way to remove items from a list, in-place, is to do it in reverse with this kind of code:

int index = list.Count - 1;
while (index >= 0)
{
if (expression identifying item to remove)
list.RemoveAt(index);
index--;
}

Now, bear in mind that this only applies to removal in a list in-place, meaning that you don't want to build a new list of the items to keep. If you can do that, build a new list with the items to keep, a LINQ expression is probably better.

So, why is the above approach preferred?

Well, consider this. What does "removing an item from a list" mean anyway? The underlying data structure of a List<T> in C# is an array. Removing an item from an array cannot really be done but what you can do is to move the values inside an array. To "remove" an item from an array you could move all the items that follow it one index up.

This is an operation that will take time relative to the number of items following it.

So let's look at doing this in the "forward approach". In this approach you would start at index 0 and move up every time you find an item to keep, but you would also remove an item by moving every item that follows it one element down.

Let's make a simple example, you have a list of every number from 1 through 10, and you want to remove every even element value (2, 4, 6, 8, etc.).

So you have this:

1 2 3 4 5 6 7 8 9 10

The first item to remove is 2, this will have to move every number that follows it, 3 through 10, one index down. That is 8 numbers moved.

The next item is 4, it will have to move 5 through 10 down, which is 6 numbers. Now we have moved 14 numbers in total.

Next is 6, move 7 through 10 down, that is 4 numbers, now we're up to 18 numbers moved.

Next is 8, move 9 and 10, 2 numbers, we're up to 20 numbers moved.

Since no numbers follow the last one we want to remove, 10, we have moved 20 numbers in total.

Now let's do it in reverse.

First we look at 10, we want to remove this, no numbers follow it, so no moving.

Next we want to remove is 8, there's only one number following it, so we move 9 down one notch. 10 was already removed so it is no longer present.

Next we want to remove is 6. There's two numbers following it, 7 and 9, so move those down, 3 numbers moved in total.

Remove 4, following it is 5, 7 and 9, so now we have moved 6 numbers in total.

Remove 2 - 3, 5, 7 and 9 is following it so now we have moved 10 numbers in total.

So when dealing with a list, it depends entirely on what you mean "behaves the same way".

Will the end result be the same, when we only consider which numbers are left in the final list?

Yes.

Will the total runtime be the same?

No.

correct way of looping through a list and remove items

You might be looking for this

for (int i = Lijst.Count - 1 ; i >= 0 ; i--)
{
if (Lijst[i].scanned == false)
{
if (Lijst[i].price > (int)nudMinimum.Value)
{
Totaal++;
lblDebug.Text = Totaal.ToString();
}
Lijst.RemoveAt(i);
}
}

Question in the comment:

why would the other direction for loop work ?

Because when the loop is run in from Zero to Count There is a situation arise when the index is not available to remove and the count is still left. For example:

if you have 10 items in the List the loop starts at 0 and would remove 0,1,2,3,4 and now the item left are 5 and index is also 5 it would remove that item too. After that when loop value reaches 6 and item left is 4. Then it would create a problem. and it would throw an error. i.e. index out of range



Related Topics



Leave a reply



Submit