17

I have the following:

foreach (var depthCard in depthCards)
{
    var card = InternalGetCard(db, depthCard.CardId);
    var set = InternalGetSet(db, (int)card.ParentSetId);
    var depthArray = InternalGetDepthArrayForCard(db, set.SetId);
    foreach (var cardToUpdate in set.Cards)
    {
        // do stuff
        SaveChanges(db);
        // since I already took care of it here, remove from depthCards
        depthCards.Remove(depthCardToUpdate);
    }
}

This isn't working though because I'm modifying the collection in the middle of a loop. Is there some type of collection that does allow this type of access?

I don't want to ToList() the depthCards because I already have them and I want to modify that list as I'm iterating. Is this possible?

Andreas
  • 5,393
  • 9
  • 44
  • 53
RobVious
  • 12,685
  • 25
  • 99
  • 181

3 Answers3

34

It's possible, the trick is to iterate backwards:

for (int i = depthCards.Count - 1; i >= 0; i--) {
  if (depthCards[i] == something) { // condition to remove element, if applicable
     depthCards.RemoveAt(i);
  }
}
Óscar López
  • 232,561
  • 37
  • 312
  • 386
8

You can iterate backwards with a for-loop

for (int i = depthCards.Count - 1; i >= 0; i--)
{
    depthCards.RemoveAt(i);
}

or if you just want to remove items on a condition, use List.RemoveAll:

depthCardToUpdate.RemoveAll(dc => conditionHere);
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • Could always add a `Where()` statement in before doing the `ForEach()` to narrow down the results before removing them, if its a conditional removal. – Bob. Jul 21 '13 at 01:57
  • @Bob.: No, because then it wouldn't be a `List` anymore but a `IEnumerable` which doesn't support the `List.ForEach` method. You could only use `foreach` then, but then it's not possible to modify the list in the loop. – Tim Schmelter Jul 21 '13 at 09:56
  • Isn't that what `ToList()` is for? – Bob. Jul 21 '13 at 16:24
  • No, ToList creates a new list. So you,re doubling the memory consumption(in the best case). – Tim Schmelter Jul 21 '13 at 16:45
  • The second code snippet still would potentially crash as it is forbidden to modify the underlying collection while iterating with ForEach. See https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.foreach?view=netframework-4.8#remarks – Vringar Nov 10 '21 at 16:52
  • 1
    @Vringar: You're right, might not work. Docs say: "Modifying the underlying collection in the body of the Action delegate is not supported and causes undefined behavior." Deleted that approach. Thanks – Tim Schmelter Nov 11 '21 at 08:10
1

You can create a custom enumerator that handles this for you. I did this once and it was a bit tricky but worked after some finesse.

See: http://www.codeproject.com/Articles/28963/Custom-Enumerators

Haney
  • 32,775
  • 8
  • 59
  • 68