13

複製

コレクションを反復しながらコレクションを変更する


列挙可能なコレクション (辞書内の IList または KeyValuePairs など) をループしているときに、オブジェクトを削除できないことを回避できるようにするための適切なパターンを誰かに教えてください。

たとえば、次の例は foreach 中に列挙されているリストを変更するため、失敗します。

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

過去に私は2つの方法を使用しました。

foreach を逆の for ループに置き換えました (オブジェクトを削除した場合にループしているインデックスを変更しないようにするため)。

また、ループ内で削除するオブジェクトの新しいコレクションを保存してから、そのコレクションをループして、元のコレクションからオブジェクトを削除しようとしました。

これらは問題なく機能しますが、どちらも気分が良くありません。誰かが問題に対するよりエレガントな解決策を思いついたのではないかと思っていました

4

7 に答える 7

13

List<T>.RemoveAll(Predicate<T> match)これのために設計されていると私が思う便利な方法があります: http://msdn.microsoft.com/en-us/library/wdka673a.aspx

于 2009-01-01T05:27:23.210 に答える
7

ちょっと単純ですが、IEnumerable/IList からアイテムを削除する場合は、通常、コピーを作成します。

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

これは最も効率的な方法ではありませんが、読みやすい方法です。時期尚早の最適化など。

于 2009-01-05T06:15:47.890 に答える
2

私はちょうどこの投稿に出くわし、共有したいと思いました.

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

}
于 2011-05-25T20:49:30.427 に答える
2

逆を行い、新しいリストを作成します。

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

次に、必要な場所で新しいリストを使用します。

また、LINQ 式を簡単に使用して、条件を逆にすることもできます。これには、新しい構造を作成しないという追加の利点がありますが、怠惰な列挙可能であるという落とし穴もあります。

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

ただし、本当にリストからアイテムを削除する必要がある場合は、通常、「新しいリストを作成してから、繰り返して削除する」アプローチを使用します。

于 2009-01-01T05:20:25.737 に答える
2

特定のデータ構造でしか機能しないため、逆の for ループのアイデアは好きではありません。

一般に、2 番目の手法を使用して、削除するアイテムを別の「削除する」コレクションに蓄積します。削除によって既存の繰り返しが無効になる可能性がある場合 (たとえば、バランスの取れたツリー コレクションで発生するように)、これを回避する方法はありません。

私が時折使用した他の唯一の手法は、削除する最初の要素を見つけたときに反復全体を再開することです。削除するアイテムが見つからない場合は、機能が終了します。これは非効率的ですが、コレクションから 1 つのアイテムを削除すると、削除する必要があるアイテムのセットが変わる可能性がある場合に必要になることがあります。

于 2009-01-01T05:20:34.940 に答える
1

私は辞書を持っていて、すべての値を破棄したいと考えています。各値が破棄されると、それ自体が辞書から削除され、議論する問題が発生します。私は次のことをしました:

foreach (var o in dictionary.Values.ToList())
{
  o.Dispose();
}
于 2012-01-13T12:40:49.267 に答える
1

これは今は死んでいるかもしれませんが、私がいつもこれを行う方法は次のとおりです。

foreach (MyListOfMyObjects 内の MyObject myObject)
{

if (条件) MyListOfMyObjects.Remove(myObject);

壊す;

}

オブジェクトが削除され、ループが終了します、ビオラ!

于 2010-04-29T17:10:37.560 に答える