3

クラス内のさまざまなアイテムの列挙子を返すクラスを持つサードパーティのAPIがあります。

その列挙子の項目を削除する必要があるため、「foreach」を使用できません。私が考えることができる唯一のオプションは、列挙型を反復処理してカウントを取得し、通常のforループを実行してアイテムを削除することです。

2つのループを回避する方法を知っている人はいますか?

ありがとう

[更新]混乱して申し訳ありませんが、コメントの以下のアンドレイは正しいです。

これは私の頭から出たいくつかの疑似コードで、機能せず、2つのループを含まないソリューションを探していますが、それは不可能だと思います。

for each (myProperty in MyProperty)
{
if (checking some criteria here)
   MyProperty.Remove(myProperty)
}

MyPropertyは、列挙子とremoveメソッドを実装するサードパーティのクラスです。

4

11 に答える 11

6

一般的なパターンは、次のようなことを行うことです。

List<Item> forDeletion = new List<Item>();

foreach (Item i in somelist)
   if (condition for deletion) forDeletion.Add(i);

foreach (Item i in forDeletion)
   somelist.Remove(i); //or how do you delete items 
于 2010-06-18T11:08:30.953 に答える
3

それを1回ループして、削除してはならない項目を含む2番目の配列を作成します。

于 2010-06-18T11:06:57.773 に答える
2

その列挙子のアイテムを削除する必要があります

これが単一のアイテムである限り、問題はありません。ルールは、コレクションを変更した後は反復を続行できないということです。したがって:

foreach (var item in collection) {
    if (item.Equals(toRemove) {
        collection.Remove(toRemove);
        break;      // <== stop iterating!!
    }
}
于 2010-06-18T12:42:22.613 に答える
2

それがコレクションであることがわかっている場合は、次の目的で元に戻すことができます。

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

それ以外の場合は、2つのループを実行する必要があります。

于 2010-06-18T11:11:10.597 に答える
2

次のようなものを作成できます。

      public IEnumerable<item> GetMyList()
    {
        foreach (var x in thirdParty )
        {
            if (x == ignore)
                continue;
            yield return x;
        }

    }
于 2010-06-18T11:14:00.753 に答える
1

列挙子からアイテムを削除することはできません。できることは、列挙シーケンス全体のコンテンツをコピーまたはフィルタリング(またはその両方)することです。linqを使用してこれを実現し、次のようにsmthを実行できます。

   YourEnumerationReturningFunction().Where(item => yourRemovalCriteria);
于 2010-06-18T11:11:25.157 に答える
1

使用しているAPIとAPI呼び出しについて詳しく教えてください。

を受け取った場合、IEnumerator<T>またはIEnumerable<T>列挙子の背後にあるシーケンスからアイテムを削除できない場合は、削除する方法がありません。もちろん、実装が変更される可能性があるため、受信したオブジェクトのダウンキャストに依存しないでください。(実際には、適切に設計されたAPIは、内部状態を保持する可変オブジェクトを公開するべきではありません。)

受信した場合、IList<T>または同様のものを受け取った場合は、通常のforループを後ろから前に使用し、状態が破損する可能性のあるイテレータがないため、必要に応じてアイテムを削除できます。(ここでは、可変状態の公開に関するルールを再度適用する必要があります。返されたコレクションを変更しても、状態は変更されません。)

于 2010-06-18T11:12:16.420 に答える
0

これを行うためのクリーンで読みやすい方法は次のとおりです(指定していないため、ここではサードパーティのコンテナーのAPIを推測しています)。

foreach(var delItem in ThirdPartyContainer.Items
                       .Where(item=>ShouldIDeleteThis(item))
                       //or: .Where(ShouldIDeleteThis)
                       .ToArray()) {
    ThirdPartyContainer.Remove(delItem);
}

.ToArray()foreachの反復が始まる前に、削除されるすべてのアイテムが貪欲にキャッシュされていることを確認するための呼び出し。

舞台裏では、これには配列とそれに対する追加の反復が含まれますが、これは一般に非常に安価であり、この質問に対する他の回答に対するこの方法の利点は、単純な列挙可能オブジェクトで機能し、トリッキーな可変状態の問題を伴わないことです。読みにくく、間違えやすい。

対照的に、逆に繰り返すことは、ロケット科学ではありませんが、1つずつエラーが発生しやすく、読みにくくなります。また、削除の合間に順序を変更しないなど、コレクションの内部に依存します(たとえば、バイナリヒープではない方がよい)。一時リストに削除する必要のあるアイテムを手動で追加することは、不要なコードです。これは、.ToArray()が問題なく実行できることです:-)。

于 2010-06-18T12:41:24.877 に答える
0

IEnumerator.Count()は、実行時に何をする必要があるかを決定します-それがコレクションであることを確認するためにカウントまたは反映するために列挙し、そのように.Countを呼び出します。

私はSJoerdの提案が好きですが、私たちが話しているアイテムの数が心配です。

于 2010-06-18T11:23:34.280 に答える
0

なぜ..のようなものではないのですか?

 // you don't want 2 and 3
 IEnumerable<int> fromAPI = Enumerable.Range(0, 10);
 IEnumerable<int> result = fromAPI.Except(new[] { 2, 3 });
于 2010-06-18T11:58:09.270 に答える
0

列挙子には、常に実際のコレクションを指すプライベートフィールドがあります。
あなたはそれをreflection.modifyを介して取得することができます。
楽しんで。

于 2010-06-19T06:53:25.603 に答える