Question

    

Cette question a déjà une réponse ici:

         

Dupliquer

Modification d'une collection en parcourant celle-ci

Quelqu'un a-t-il un bon motif pour me permettre de contourner l'impossibilité de supprimer des objets lorsque je parcours en boucle une collection énumérable (par exemple, un IList ou un KeyValuePairs dans un dictionnaire)

Par exemple, ce qui suit échoue, car il modifie la liste énumérée lors de la foreach

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

Dans le passé, j'ai utilisé deux méthodes.

J'ai remplacé le foreach par une boucle for inversée (pour ne pas modifier les index sur lesquels je boucle si je supprime un objet).

J'ai également essayé de stocker une nouvelle collection d'objets à supprimer dans une boucle, puis de parcourir en boucle cette collection et de supprimer les objets de la collection d'origine.

Cela fonctionne bien, mais ne se sent pas bien et je me demandais si quelqu'un avait proposé une solution plus élégante au problème

.
Était-ce utile?

La solution

Il existe une List<T>.RemoveAll(Predicate<T> match) méthode utile qui, à mon avis, est conçue à cet effet: http : //msdn.microsoft.com/en-us/library/wdka673a.aspx

Autres conseils

C'est un peu simple d'esprit, mais lorsque je projette de supprimer des éléments d'un IEnumerable / IList, je fais généralement une copie:

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

Ce n’est pas le moyen le plus efficace de le faire, mais il est facile à lire. Optimisation prématurée et tout ça.

Faites l'inverse en créant une nouvelle liste:

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

Utilisez ensuite la nouvelle liste partout où vous en avez besoin.

Vous pouvez également utiliser facilement une expression LINQ, inversant ainsi la condition. Cela présente l’avantage supplémentaire de ne pas créer de nouvelle structure, mais aussi d’avoir un piège à énumérer:

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

Cependant, si vous avez vraiment besoin de supprimer les éléments de la liste, j'utilise généralement le & "créer une nouvelle liste, puis réitérer et supprimer &"; approche.

Je viens de tomber sur ce post et je pensais partager.

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);

}

Je n'aime pas l'idée de la boucle for inversée, car elle ne fonctionne que sur certaines structures de données.

En général, j'utiliserais la deuxième technique et accumulerais les éléments à supprimer dans une collection séparée "à supprimer". Si la suppression peut entraîner l'invalidation d'itérations existantes (comme cela se produira avec n'importe quelle collection d'arbres équilibrée, par exemple), je ne vois pas comment y remédier.

La seule autre technique que j'ai parfois utilisée consiste à redémarrer l'itération complète lorsque vous trouvez le premier élément à supprimer. Si vous réussissez sans trouver d'éléments à supprimer, la fonction est terminée. Ceci est inefficace, mais parfois nécessaire si la suppression d’un élément de la collection peut modifier l’ensemble des éléments à supprimer.

J'ai un dictionnaire et je veux éliminer toutes les valeurs. Lorsque chaque valeur est supprimée, elle disparaît du dictionnaire, ce qui crée le problème dont vous parlez. J'ai fait ce qui suit:

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

J'apprécie que cela soit peut-être mort maintenant mais la façon dont je le fais toujours est la suivante:

foreach (MyObject myObject dans MyListOfMyObjects)
{

if (condition) MyListOfMyObjects.Remove (myObject);

pause;

}

L'objet est supprimé, puis la boucle se ferme, alto!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top