反復中にsortedListから削除するのは安全ですか?
-
01-10-2019 - |
質問
私の質問は、列挙者がsortedlistからアイテムを削除するのは安全ですか?
SortedList<decimal, string> myDictionary;
// omitted code
IEnumerator<decimal, string> enum = myDictionary.GetEnumerator();
while(enum.MoveNext)
{
// is it ok to remove here?
myDictionary.Remove(enum.Current.Key);
}
解決
これにより、例外がスローされます - コレクションを反復しながらコレクションを変更することはできません。
少し考えれば、その理由がわかります。コレクションから追加または削除が許可された場合、同じコレクションを反復することはなくなりました - あまりにも多く(追加)または十分なアイテム(削除)がありません。
他のヒント
すでに述べたように、あなたがやりたいことは不可能です。ただし、別の解決策は、削除のためにマークされたアイテムのリストを単純に維持し、これらのあ得子を削除することです。私も選択します foreach
ではなく while
ループ、コードが少ない
var removeList = new List<decimal>();
foreach (var item in myDictionary)
{
// have a condition which indicates which items are to be removed
if (item.Key > 1)
{
removeList.Add(item.Key);
}
}
または、単に削除のためにアイテムを取得しようとしている場合は、linqを使用してください
var removeList = myDictionary.Where(pair => pair.Key > 1).Select(k => k.Key).ToList();
次に、リストからそれらを削除するだけです。
// remove from the main collection
foreach (var key in removeList)
{
myDictionary.Remove(key);
}
反復中のリストの操作は、一般的にはサポートされていません。予想される動作は例外をスローすることですが、コレクションがこれを実行できなかったとしても、この動作に正しく頼ってはなりません。
最初に要素を別のリストにコピーしてから、変更するアイテムのこの新しいリストを反復することができます。
いいえ。NIVALIDOPERATIONEXCPETIONがスローされます。固定インデックスがあるため、既に列挙されたアイテムが削除可能である可能性があることに同意します。ただし、問題は次のとおりです。
sortedlistの実装は、除去が列挙可能なもののさらなる実行に影響を与えないことを理解するほど賢くありません。そして、シンプルでパフォーマンスを維持するためには、そうすべきではありません。
他の人がすでに指摘しているように、それはうまくいきません。ただし、コレクションはsortedListであるため、Removeatメソッドを使用できます。
この方法は、除去を追跡するために個別のリストを使用してO(n)の増加とは対照的にオーバーヘッドを必要としないため、わずかに優れたメモリプロファイルを持っています。また、O(n^2 * log(n))とは対照的に、O(n^2)パフォーマンスプロファイルもあります。 Removeatメソッドは、配列コピーを実行する必要があるため、O(n)です。削除メソッドは、内部的に呼び出す前にインデックスを見つけるためにO(log(n))操作を追加します。これらはすべておそらくあなたにとっては心配ではありませんが、多くの「n」が含まれる状況に遭遇した場合には有益です。
var myDictionary = new SortedList<decimal, string>();
// omitted code
int i = 0;
while (myDictionary.Count > 0 && i < myDictionary.Count)
{
if (/* predicate to use for removal */)
{
myDictionary.RemoveAt(i);
}
else
{
i++;
}
}
他の解決策:
int counter= MyDictionary.Count;
if (counter == 0)
return;
for (int i = 0; i < counter;i++)
{
KeyValuePair<MyIdentifier, MyValue> key = (KeyValuePair<MyIdentifier, MyValue>)MyDictionary.ToArray()[i];
MyIdentifier identifier = null;
if (key.Key != null)
identifier = key.Key as MyIdentifier;
if (identifier != null)
if (MyCondition)
{
MyDictionary.Remove(identifier);
counter--;
}
}