47

次のようにしたいコードがあります。

List<Type> Os;

...

foreach (Type o in Os)
    if (o.cond)
        return;  // Quitting early is important for my case!
    else
        Os.Remove(o);

... // Other code

foreachリストのループ内にいるときはリストから削除できないため、これは機能しません。

問題を解決する一般的な方法はありますか?

必要に応じて別のタイプに切り替えることができます。

オプション 2:

List<Type> Os;

...

while (Os.Count != 0)
     if (Os[0].cond)
         return;
     else
         Os.RemoveAt(0);

... // Other code

醜いですが、うまくいくはずです。

4

17 に答える 17

59

リストを逆方向に繰り返すことができます。

for (int i = myList.Count - 1; i >= 0; i--)
{
    if (whatever) myList.RemoveAt(i);
}

削除していないアイテムを見つけたときに終了したいというコメントに応えて、while ループを使用するのが最善の解決策です。

于 2009-05-06T22:47:19.503 に答える
55

foreach ループ内で繰り返し処理しているコレクションから何も削除しないでください。それは基本的に、座っている枝をのこぎりで切るようなものです。

while 代替を使用します。それは行く道です。

于 2009-05-06T22:48:24.757 に答える
13

分析ライブラリでその問題が発生しました。私はこれを試しました:

for (int i = 0; i < list.Count; i++)
{                
   if (/*condition*/)
   {
       list.RemoveAt(i);
       i--;
   }
}

とてもシンプルですが、ブレークポイントは考えていません。

于 2009-05-06T23:06:50.377 に答える
12

これが最もシンプルな理由による最も簡単なソリューションです

問題:

通常、元のリストから削除します。これにより、リスト数とイテレータの場所を維持するという問題が発生します。

List<Type> Os = ....;
Os.ForEach(
    delegate(Type o) {
        if(!o.cond) Os.Remove(o);
    }
);

解決策- LINQ.ForEach

私が追加したのは。だけだったことに注意してくださいToList()。これにより、ForEachを実行する新しいリストが作成されるため、元のリストを削除しながら、リスト全体を繰り返し処理することができます。

List<Type> Os = ....;
Os.ToList().ForEach(
    delegate(Type o) {
        if(!o.cond) Os.Remove(o);
    }
);

解決策-通常foreach

この手法は、通常のforeachステートメントでも機能します。

List<Type> Os = ....;
foreach(Type o in Os.ToList()) {
  if(!o.cond) Os.Remove(o);
}

struct元のリストに要素が含まれている場合、このソリューションは機能しないことに注意してください。

于 2012-02-21T17:08:09.027 に答える
11

あなたが何か他のことを要求したことは知っていますが、条件付きで一連の要素を削除したい場合は、ラムダ式を使用できます。

Os.RemoveAll(o => !o.cond);
于 2010-08-30T17:56:22.147 に答える
9
 Os.RemoveAll(delegate(int x) { return /// });
于 2009-05-06T22:47:52.793 に答える
4

述語を満たさない最初の項目のインデックスを見つけて、それに対して RemoveRange(0, index) を実行します。他に何もないとしても、Remove 呼び出しは少なくなるはずです。

于 2009-05-06T23:01:59.577 に答える
2

あなたはlinqでそれを行うことができます

MyList = MyList.Where(x=>(someCondition(x)==true)).ToList()
于 2013-03-12T14:14:04.330 に答える
1

これについては、繰り返しながらリスト内の項目を削除するで適切な議論があります。

彼らは提案します:

for(int i = 0; i < count; i++)
{
    int elementToRemove = list.Find(<Predicate to find the element>);

    list.Remove(elementToRemove);
}
于 2009-05-06T22:46:29.660 に答える
1

リストがそれほど大きくないことがわかっている場合は、使用できます

foreach (Type o in new List<Type>(Os))
    ....

これにより、リストの一時的な複製が作成されます。remove() 呼び出しは、イテレータに干渉しません。

于 2009-05-06T22:53:48.100 に答える
1

見るEnumerable.SkipWhile()

Enumerable.SkipWhile( x => condition).ToList()

通常、リストを変更しないと、ライブがずっと簡単になります。:)

于 2009-06-06T13:49:13.947 に答える
1

Anzurio のソリューションはおそらく最も簡単ですが、ユーティリティ ライブラリに多数のインターフェイス/クラスを追加することを気にしない場合は、別のクリーンなソリューションを次に示します。

このように書くことができます

List<Type> Os;
...
var en = Os.GetRemovableEnumerator();
while (en.MoveNext())
{
    if (en.Current.Cond)
        en.Remove();
}

Java のIterator<T>.removeに触発された次のインフラストラクチャをユーティリティ ライブラリに追加します。

static class Extensions
{
    public static IRemovableEnumerator<T> GetRemovableEnumerator<T>(this IList<T> l)
    {
        return new ListRemovableEnumerator<T>(l);
    }
}

interface IRemovableEnumerator<T> : IEnumerator<T>
{
    void Remove();
}

class ListRemovableEnumerator<T> : IRemovableEnumerator<T>
{
    private readonly IList<T> _list;
    private int _count;
    private int _index;
    public ListRemovableEnumerator(IList<T> list)
    {
        _list = list;
        _count = list.Count;
        _index = -1;
    }

    private void ThrowOnModification()
    {
        if (_list.Count != _count)
            throw new InvalidOperationException("List was modified after creation of enumerator");
    }
    public void Dispose()
    {
    }

    public bool MoveNext()
    {
        ThrowOnModification();
        if (_index + 1 == _count)
            return false;
        _index++;
        return true;
    }

    public void Reset()
    {
        ThrowOnModification();
        _index = -1;
    }

    object IEnumerator.Current
    {
        get { return Current; }
    }

    public T Current
    {
        get { return _list[_index]; }
    }

    public void Remove()
    {
        ThrowOnModification();
        _list.RemoveAt(_index);
        _index--;
        _count--;
    }
}
于 2013-11-29T02:11:08.167 に答える
0

私はちょうど同じ問題を抱えていて、以下を使用して解決しました:

foreach (Type o in (new List(Os))) { if (something) Os.Remove(o); }

リストのコピーを反復処理し、元のリストから削除します。

于 2014-06-05T07:58:43.443 に答える