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.