Vra

    

Hierdie vraag het reeds 'n antwoord hier:

         

Dubbele

wysiging van 'n Versameling Terwyl iterating Deur Dit


Het iemand 'n lekker patroon om my om die onvermoë om voorwerpe te verwyder te kry terwyl ek lus deur 'n enumerable versameling (bv, 'n IList of KeyValuePairs in 'n woordeboek)

Byvoorbeeld, die volgende versuim, as dit verander die lys word oor vervat in die foreach

foreach (MyObject myObject in MyListOfMyObjects)
{
     if (condition) MyListOfMyObjects.Remove(myObject);
}

In die verlede het ek twee metodes wat gebruik word.

Ek het die foreach met vervang 'n omgekeerde for-lus (sodat dit nie die enige indekse Ek herhaling oor te skakel as ek 'n voorwerp te verwyder).

Ek het ook probeer stoor 'n nuwe versameling van voorwerpe binne te loop om te verwyder, dan herhaling deur daardie versameling en verwyder die voorwerpe van die oorspronklike versameling.

Hierdie werk goed, maar nie voel mooi, en ek het gewonder of iemand met gekom 'n meer elegante oplossing vir die probleem

Was dit nuttig?

Oplossing

Daar is 'n nuttige List<T>.RemoveAll(Predicate<T> match) metode wat ek dink is ontwerp vir hierdie: http: / /msdn.microsoft.com/en-us/library/wdka673a.aspx

Ander wenke

Dit is soort van 'n eenvoudige-minded, maar toe ek van plan is om items uit 'n IEnumerable / IList verwyder ek gewoonlik net 'n kopie te maak:

foreach (MyObject myObject in new List<MyObject>(MyListOfMyObjects))
{
     if (condition) MyListOfMyObjects.Remove(myObject);
}

Dit is nie die mees doeltreffende manier om dit te doen, maar dit is maklik om te lees. Voortydige optimalisering en alles wat.

Voer die omgekeerde, die skep van 'n nuwe lys:

List myFilteredList = new List();
foreach (MyObject myObject in myListOfMyObjects)
{
     if (!condition) myFilteredList.Add(myObject);
}

Gebruik dan die nuwe lys waar jy dit nodig het.

Jy kan ook maklik gebruik 'n LINQ uitdrukking, weer, inversing die toestand. Dit het die bykomende voordeel van nie 'n nuwe struktuur, maar ook die slaggate van dit wat 'n lui enumerable:

var myFilteredList = from myObject in myListOfMyObjects
                     where !condition
                     select myObject;

As jy egter werklik nodig het om die items uit die lys te verwyder, gebruik ek gewoonlik die "skep 'n nuwe lys, dan herhaal en verwyder" benadering.

Ek het net oor hierdie post en gedink ek sou deel.

void RemoveAll(object condition)  
{

    bool found = false;

    foreach(object thisObject in objects)    
    {

        if (condition)    
        {    
            objects.Remove(thisObject);

            found = true;

            break; //exit loop    
        }     
     }

    // Call again recursively

    if (found) RemoveAll(condition);

}

Ek hou nie van die omgekeerde vir lus idee, want dit werk net op sekere data strukture.

In die algemeen Ek sal die tweede tegniek gebruik en versamel die items in 'n aparte 'to-be-verwyder 'n versameling te verwyder. As skrap bestaande iterate kan veroorsaak word ongeldig verklaar (soos sal gebeur met enige gebalanseerde boom versameling byvoorbeeld) dan kan ek nie sien 'n manier om hierdie.

Die enigste ander tegniek wat ek van tyd tot tyd gebruik het om die hele iterasie herlaai wanneer jy die eerste element te verwyder vind. As jy dit maak deur sonder om enige items te verwyder dan die funksie is klaar. Dit is ondoeltreffend, maar soms nodige indien die verwydering van een item uit die versameling van die stel van items wat nodig het om te verwyder, kan verander.

Ek het 'n woordeboek en wil ontslae van alle waardes. Wanneer elke waarde is van die hand gesit dit verwyder hom van die woordeboek wat die probleem wat jy bespreek skep. Ek het die volgende:

foreach (var o in dictionary.Values.ToList())
{
  o.Dispose();
}

Ek waardeer dit kan nou dood, maar die manier wat ek dit altyd doen, is:

foreach (MyObject myObject in MyListOfMyObjects)
{

As (toestand) MyListOfMyObjects.Remove (myObject);

breek;

}

Object verwyder en dan lus uitgange, altviool!

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top