views:

49

answers:

4

I have a String Collection that is populated with ID's like so -->

12345
23456
34567

and so on. What I need to do is at the user's request, and when certain parameters are met, go through that list, starting at the top, and perform a method() using that ID. If successful I would remove it from the list and move on.

I, embarrassingly, have never worked with a collection before in this manner. Can someone point me in the right direction. Examples all seem to be of the Console.Writeline(""); variety.

My base, ignorant, attempt looks like this -->

 var driUps = Settings.Default.DRIUpdates.GetEnumerator();
        while (driUps.MoveNext())
        {
            var wasSuccessfull = PerformDRIUpdate(driUps.Current);
            if (wasSuccessfull)
            {
                driUps.Current.Remove(driUps.Current.IndexOf(driUps.Current));
            }
        }

The part I am most concerned with is the Remove(); Isn't there a better way to get the Current Index? Any and all Tips, Hints, Criticism, Pointers, etc....welcome. Thanks!

+4  A: 

You are quite right to be concerned about the 'remove' during enumeration. How about somethign like this:

int idx = 0;
while (idx < strCol.Count)
{
    var wasSuccessful = PerformDRIUpdate(strCol[idx]);
    if (wasSuccessful)
        strCol.RemoveAt(idx);
    else
        ++idx;
}
n8wrl
This also avoids the problem of invalidating the enumerator when removing an item from the collection. +1
TreDubZedd
@n8wrl +1 for providing a solution that doesn't use an enumerator, for the "collection modified whilst enumerating" issue. Dependant on the size of the collection, but I usually loop these backwards for performance reasons to prevent re-building of the internal collection.
chibacity
@chibacity: By looping backwards you would "reverse" the `while` condition, essentially? And the `idx = strCol.Count`?
Refracted Paladin
@Refracted There's a little more to it than that. Please see my answer.
chibacity
A: 

Iterating an enumerator is best done with the foreach(), it does a GetEnumerator() and creates a similar block under the covers to what you're getting at, the syntax is:

foreach(ObjectType objectInstance in objectInstanceCollection)
{
    do something to object instance;
}

for you,

List<DRIUpdate> updatesToRemove = new List<DRIUpdate>();
foreach(DRIUpdate driUpdate in Settings.Default.DRIUpdates)
{
    if (PerformDRIUpdate(driUpdate))
    {
        updatesToRemove.Add(driUpdate);
    }
}

foreach(DRIUpdate driUpdate in updatesToRemove)
{
    Settings.Default.DRIUpdates.Remove(driUpdate);
}
Jimmy Hoffa
A: 

If driUps is an IEnumerable<T>, try this:

driUps = driUps.Where(elem => !PerformDRIUpdate(elem));

Update:

From the example, it seems this is more appropriate:

Settings.Default.DRIUpdates = 
  Settings.Default.DRIUpdates.Where(elem => !PerformDRIUpdate(elem));

For a List<T>, it's simpler:

list.RemoveAll(PerformDRIUpdate);
Jordão
+1  A: 

As suggested by n8wrl, using RemoveAt solves the issue of trying to remove an item whilst enumerating the collection, but for large collections removing items from the front can cause performance issues as the underlying collection is re-built. Work your way from the end of the collection and remove items from that end:

//Loop backwards, as removing from the beginning
//causes underlying collection to be re-built
int index = (strCol.Count - 1);

while (index >= 0)
{
    if (PerformDRIUpdate(strCol[index]))
    { 
        strCol.RemoveAt(index);
    }

    --index;
}
chibacity
Thanks, not really an issue for me as this list will never be more then, say 20 items, but it is always good to know a "best practice". I only wish there was half answers I could award. Anyway, thanks for taking the time.
Refracted Paladin
@Refracted That would be nice. Just happy to pass the knowledge on :)
chibacity