8

基本的に、 foreach ループ内でリストからアイテムを削除したいと思います。forループを使用するとこれが可能であることはわかっていますが、他の目的のために、foreachループを使用してこれが達成可能かどうかを知りたいです。

Python では、次のようにしてこれを実現できます。

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

for i in a:
    print i

    if i == 1:
        a.pop(1)

これにより、次の出力が得られます

>>>1
3
4
5
6
7
8
9

しかし、c# で似たようなことをすると、InvalidOperationException が発生します。単純に for ループを使用せずに、これを回避する方法があるかどうか疑問に思っていました。

例外がスローされたときに使用した c# のコード:

static void Main(string[] args)
  {
  List<string> MyList = new List<string>(new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9"});

  foreach (string Item in MyList)
    {
    if (MyList.IndexOf(Item) == 0)
      {
      MyList.RemoveAt(1);
      }

    Console.WriteLine(Item);
    }
  }

前もって感謝します

4

3 に答える 3

26

これはできません。のドキュメントからIEnumerator<T>

コレクションが変更されない限り、列挙子は有効なままです。要素の追加、変更、または削除などの変更がコレクションに加えられた場合、列挙子は回復できないほど無効になり、その動作は未定義になります。

代替手段は次のとおりです。

  • 削除するアイテムの新しいリストを作成し、後でそれらをすべて削除します
  • 通常の「for」ループを使用し、同じ要素を 2 回繰り返したり、見落としたりしないように注意してください。(あなたはこれをしたくないと言ったが、あなたがやろうとしていることはうまくいかない. )
  • 保持したい要素のみを含む新しいコレクションを構築します

これらの選択肢の最後は LINQ のようなソリューションで、通常は次のように記述します。

var newList = oldList.Where(x => ShouldBeRetained(x)).ToList();

ShouldBeRetainedもちろん、必要なロジックはどこにありますか。)への呼び出しToList()は、実際にリストに入れたい場合にのみ必要です。これにより、より宣言的なコードが読みやすくなります。元のループが何をするつもりなのか簡単に推測できません (現時点ではかなり奇妙に思えます) が、項目に関して純粋にロジックを表現できれば、はるかに明確になります。

于 2009-07-14T08:53:09.813 に答える
6

条件を満たすすべてのアイテムを削除するだけでよい場合は、List<T>.RemoveAllメソッドを使用できます。

List<string> MyList = new List<string>(new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9" });
MyList.RemoveAll(item => item == "1");

これにより初期リストが変更されることに注意してください。

于 2009-07-14T09:10:59.153 に答える
1

foreach ループを使用する場合、コレクションを変更することはできません。

for ループを使用して自分でインデックスを管理するか、コレクションのコピーを作成して、元のアイテムをループしているときに、元のアイテムと同じアイテムをコピーから削除することができます。

どちらの場合も、それほど明確でも便利でもありません:)。

于 2009-07-14T08:54:16.893 に答える