227 votes

Modification de valeurs de dictionnaire dans une boucle foreach

Je et en essayant de construire un graphique à partir d'un dictionnaire. Avant de m'afficher le graphique à secteurs, je veux mettre de l'ordre dans les données. Je suis à la suppression de toute secteurs qui seraient à moins de 5% de la tarte et la mettre dans un "Autre" tarte. Cependant j'ai une Collection a été modifiée; opération d'énumération ne peut pas exécuter d'exception à l'exécution.

Je comprends pourquoi vous ne pouvez pas ajouter ou supprimer des éléments à partir d'un dictionnaire tout en évoluant au-dessus d'eux. Cependant, je ne comprends pas pourquoi vous ne pouvez pas il suffit de changer une valeur pour une clé existante à l'intérieur de la boucle foreach.

Toutes les suggestions re: correction de mon code, serait appréciée.

Dictionary<string, int> colStates = new Dictionary<string,int>();
// ...
// Some code to populate colStates dictionary
// ...

int OtherCount = 0;

foreach(string key in colStates.Keys)
{

    double  Percent = colStates[key] / TotalCount;

    if (Percent < 0.05)
    {
        OtherCount += colStates[key];
        colStates[key] = 0;
    }
}

colStates.Add("Other", OtherCount);

292voto

Jon Skeet Points 692016

La définition de la valeur dans un dictionnaire des mises à jour de son système interne de "numéro de version" - ce qui invalide l'itérateur, et tout itérateur associé avec les touches ou les valeurs de la collection.

Je ne comprends votre point, mais en même temps, il serait étrange si les valeurs de la collection pourrait changer la mi-itération - et pour des raisons de simplicité il n'y a qu'un numéro de version.

La manière normale de la fixation de ce genre de chose est de copier l'ensemble de clés à l'avance et effectuer une itération sur la copie, ou de parcourir la collection d'origine, mais de maintenir une collection de modifications lequel vous allez appliquer une fois que vous avez fini de l'itération.

Par exemple:

La copie de clés d'abord

List<string> keys = new List<string>(colStates.Keys);
foreach(string key in keys)
{
    double percent = colStates[key] / TotalCount;    
    if (percent < 0.05)
    {
        OtherCount += colStates[key];
        colStates[key] = 0;
    }
}

Ou...

Création d'une liste de modifications

List<string> keysToNuke = new List<string>();
foreach(string key in colStates.Keys)
{
    double percent = colStates[key] / TotalCount;    
    if (percent < 0.05)
    {
        OtherCount += colStates[key];
        keysToNuke.Add(key);
    }
}
foreach (string key in keysToNuke)
{
    colStates[key] = 0;
}

109voto

DIG Points 35

Voici une autre façon de le faire :

Le ToList() pourrait avoir le même effet que d’autres solutions ici mais ne nécessite pas une nouvelle variable temp.

22voto

CodeFusionMobile Points 6173

Vous êtes à la modification de la collecte de cette ligne:

colStates[clé] = 0;

Ce faisant, vous êtes essentiellement de la suppression et de la réinsertion de quelque chose (comme la mesure IEnumerable est concerné, de toute façon.

Si vous modifiez un membre de la valeur stockée, ce serait OK, mais vous modifiez la valeur elle-même et IEnumberable n'aime pas cela.

La solution que j'ai utilisé est d'éliminer la boucle foreach et il suffit d'utiliser une boucle for. Une simple boucle for ne pas vérifier les modifications que vous savez ne pas en effet de la collection.

Voici comment vous pouvez le faire:

List<string> keys = new List<string>(colStates.Keys);
for(int i = 0; i < keys.Count; i++)
{
    string key = keys[i];
    double  Percent = colStates[key] / TotalCount;
    if (Percent < 0.05)    
    {        
        OtherCount += colStates[key];
        colStates[key] = 0;    
    }
}

6voto

Jeremy Frey Points 1463

Vous ne pouvez pas modifier les clés, ni les valeurs directement dans une instruction ForEach, mais vous pouvez modifier leurs membres. Par exemple, cela devrait fonctionner :

3voto

Scott Ivey Points 19577

Pourquoi ne faire quelques requêtes de linq sur votre dictionnaire et puis en y liant votre graphique pour les résultats de ceux ?...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X