2011-09-30 5 views
9

のは、私はいくつかのコードがあるとしましょう:IEnumerableを複数回を読む

var items = ItemsGetter.GetAllItems().Where(x => x.SomeProperty > 20); 
int sum1 = items.Sum(x => x.SomeFlag == true); 

をし、例えば、私は、後のコード内の項目のコレクションからいくつかの他の合計を必要とします。

int sum2 = items.Sum(x => x.OtherFlag == false); 

私の質問:IEnumerableでLinqメソッドを複数回呼び出すことはできますか?たぶん私は列挙型でReset()メソッドを呼び出すか、ToListメソッドを使用してアイテムからリストを作成する必要がありますか?

答えて

16

まあ、本当にあなたがしたいことに依存しています。それはだ後は

var items = ItemsGetter.GetAllItems().Where(x => x.SomeProperty > 20).ToList(); 

またははあなたがリストに結果をコピーするヒットを取ることができる、あなたは二回のクエリを実行するのヒットを取ることができる(およびその正確な意味はGetAllItems()が何をするかに依存します)リスト内では、明らかに、そのリストを複数回反復することは問題ではありません。

Resetは、イテレータがないので呼び出すことはできません。つまり、IEnumerable<T>です。とにかくIEnumerator<T>を呼び出すことはお勧めできません。多くの実装(イテレータブロックからC#コンパイラによって生成されたものを含む)は実際にはResetを実装していません(例外をスローします)。

1

LINQは遅延実行を使用するため、「アイテム」は別の方法で要求したときにのみ列挙されます。各SumメソッドはO(n)を繰り返し処理します。アイテムリストの大きさによっては、複数回反復したくない場合があります。

+0

これはありません"IEnumerableでLinqメソッドを複数回呼び出すことはできますか?"という質問に答えてください。 ... 答えはいいえだ"。 –

+0

さて、「OK」とは、少し不明であることを意味します。あなたは何回でもリストを反復することができます。私は私の答えでこれの結果を言及します。どのようにそれらを反復することができないのですか?もしあなたがそうだと思うなら、あなた自身の答えを投稿してください(すでに受け入れられている回答があります)。 –

+0

これは完全にはっきりしています。 'items'はIEnumerableであり、リストではありません。あなたはそれを一度しかトラバースできません。別の回答を投稿する必要はありませんが、読者はこの回答が間違っていて、質問に触れていないことを理解することが重要です。 –

3

時々、列挙型を複数回処理する必要がある状況です。列挙が高価で反復不可能で、(データベースから読み取るIQueryableのような)多数のデータを生成する場合、複数の列挙はオプションではなく、結果をメモリにバッファリングしません。

今日まで、foreachループでアイテムをプッシュして結果を読み取ることができるアグリゲータクラスを作成してしまいました.LINQよりははるかにエレガントです。

しかし、私はちょうど "プッシュ"と言ったのですか?それは反応するようには聞こえませんか?だから私は今夜の散歩中に考えていた。私はそれを試してみました - それは動作します!

例スニペットが受信(Rxのもの、つまり)標準LINQ演算子を使用して、単一パスの整数の配列から最小値および最大アイテムの両方を取得する方法を示しています。

public static MinMax GetMinMax(IEnumerable<int> source) 
{ 
    // convert source to an observable that does not enumerate (yet) when subscribed to 
    var connectable = source.ToObservable(Scheduler.Immediate).Publish(); 

    // set up multiple consumers 
    var minimum = connectable.Min(); 
    var maximum = connectable.Max(); 

    // combine into final result 
    var final = minimum.CombineLatest(maximum, (min, max) => new MinMax { Min = min, Max = max }); 

    // make final subscribe to consumers, which in turn subscribe to the connectable observable 
    var resultAsync = final.GetAwaiter(); 

    // now that everybody is listening, enumerate! 
    connectable.Connect(); 

    // result available now 
    return resultAsync.GetResult(); 
} 
関連する問題