1

I am iterating over a collection and want to delete some entries of it. Example:

For i = 0 To Node.Nodes.Count
    If i >= args.TotalNumberOfNodes Then
        Node.Nodes.RemoveAt(i)
    End If
Next i

As you can see, if one condition is true, I want to delete the item from the collection. If I pass now a List of 20 items into this, what happens is that every 2nd element gets deleted for an obvious reason: If the item should be removed, it gets removed which decreases the list size by 1 and then i is incremented by one which leaves the then current element out.

Another (working) approach is:

For i = 0 To Node.Nodes.Count
    If i >= args.TotalNumberOfNodes Then
        Node.Nodes.RemoveAt(i)
        i = i - 1
    End If
Next i

This technique decrements i by 1 before it gets incremented at the end of the for loop resulting in the same i as before. Since this seems to me a bit like bad design and it is not completely easy to understand for readers, I would like to know if there is any better way to remove items from a list but not skipping the next item from this list.

In addition to this, with a for each loop it throws me an exception because it tries to iterate over the list which is currently being altered. On a different posting, I saw the approach of adding all to a new list and then using a removeAll method. This would work technically but for performance reasons I would like to manipulate the list as I walk over it.

  • If there are no threading concerns, and the code is localized, I'd probably do the decrement during traversal. You won't be able to substitute for different iterators as easily, but if the code is localized, you can change it all right there if you choose a different iteration method. Some languages allow deletion of the item referred to at the current position of the iterator so this is handled more naturally, of course, you'd be using a foreach instead of for i; Other methods involve traversing backwards... – Erik Eidt May 20 '16 at 0:16
  • Interestingly, if I use a for each it deletes the current element, then jumps via next to the next element. This results in skipping every other element. – Freddy May 20 '16 at 17:47
  • Sorry, not familiar with VB.Net's foreach constructs, thought it was like C#, my bad. – Erik Eidt May 20 '16 at 17:56
  • Let me try this out in C# and then come back to you. – Freddy May 20 '16 at 17:58
  • C# gives me an InvalidOperationException if I try to modify the list I am iterating over, see github.com/f-ewald/ListIterationExample – Freddy May 20 '16 at 18:09
4

Since lists grow and shrink from their end, you can easily solve the problem by simply looping over the list in reverse order.

For i = Node.Nodes.Count-1 To 0 Step -1
    If SomeCondition Then
        Node.Nodes.RemoveAt(i)
    End If
Next i
  • I accepted this solution because I think this is a general approach how to solve different problems when manipulating lists while iterating over them. Although I have to say that a decremented i feels not natural to me. – Freddy May 20 '16 at 17:51
1

You can use a Do loop to perform the same task:

    Do
        myCollection.RemoveAt(MaxCount)
    Loop Until myCollection.Count = MaxCount

This will remove individual collection elements at your maximum count value.

There is also a Do ... Loop While variation of the loop.

You can find out more about VB's loop structures here.

  • 1
    I like this solution a lot and it looks very clean to me. – Freddy May 20 '16 at 17:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.