1. ホーム
  2. c#

[解決済み】foreachループで辞書の値を編集する

2022-04-06 20:18:47

質問

辞書から円グラフを作成しようとしています。円グラフを表示する前に、データを整頓したいのです。円グラフの5%に満たない円グラフを削除して、「その他」の円グラフに入れました。しかし Collection was modified; enumeration operation may not execute 例外が発生します。

辞書の反復処理中に項目の追加や削除ができない理由は理解しています。しかし、foreachループの中で既存のキーの値を単純に変更できない理由は理解できません。

私のコードの修正について、何かご提案がありましたら、お願いします。

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

解決方法は?

辞書に値を設定すると、内部の "バージョン番号" が更新され、イテレータと、キーまたは値のコレクションに関連付けられたすべてのイテレータが無効になります。

しかし同時に、値のコレクションが反復の途中で変更されるとしたら、それは奇妙なことです。

この種の問題を解決する通常の方法は、キーのコレクションをあらかじめコピーしておき、そのコピーに対して反復処理を行うか、元のコレクションに対して反復処理を行うが、反復処理が終わった後に適用する変更点のコレクションを維持することです。

例えば

キーを先にコピーする

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

または...

モディファイリストの作成

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