2016-11-11 8 views
4

LINQには、列挙型をカウントする2つの方法、CountおよびLongCountがあります。実際には、これらの2つの唯一の違いは、最初はintを返し、2番目はlongを返します。LINQのLongCount拡張メソッドが追加された実用的な理由はありますか?

2番目の方法が追加された理由は不明です。唯一のユースケースは2B以上の要素の列挙型を処理することだと思われます。これは、いくつかの理由のために、私には貧しい意思決定のように思える:

  1. ほとんどBCLコレクションはintに収まるように保証されている長さを有している単一次元配列によって支えられています。それを過ぎようとするとOverflowException/OutOfMemoryExceptionが発生します。

  2. LongCountIEnumerableが遅延であるためO(n)です。 3B要素を列挙できる場合は、LongCountを呼び出してから、もう一度繰り返します(値を使用する必要がある場合)。余分な3B繰り返しを追加します。非常に遅く、開発者から隠れてしまいます。

  3. ToArray/ToListのような他のLINQ演算では、(1)のために2B +要素の列挙型をサポートしません。

私はここに何かがないか、もっと具体的な理由はLongCountが追加されましたか?ありがとう。

+0

ソースコード 'LongCount'に基づいて' Enumerator.MoveNext'で 'IEnumerable'を繰り返し、' Count'は 'ICollection'に' IEnumerable'をキャストしようとし、キャストが失敗した場合は 'Count'を使って反復します'IEnumerable'と同じ方法で' LongCount'を呼び出します。 [https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,d76b4b5d3fd67767](https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs、 d76b4b5d3fd67767)。 @EricLipertによるこの "推測"に基づいて、非常に論理的なようです。 – Fabio

+0

@Fabio、それは単なる最適化です。意味的には 'LongCount'が' ICollection'をチェックして結果を 'long'にキャストするだけですが、' LongCount'はそれほど使われないので、そうしていないのです。 –

答えて

4

私はこのデザインの決定についての最初の知識は持っていませんが、私は教育的な推測を提供することができます。

この方法は、IQueryableの明らかな有用性です。クエリは膨大なデータベーステーブルによって容易にバックアップされる可能性があります。

私は

IQueryable<Foo> q = whatever; 
long result1 = q.LongCount(); 
long result2 = q.AsEnumerable().LongCount(); 

が同じ答えを生み出すことを期待します。特に、列挙可能なバージョンを実装するのが簡単な場合は、異なる型を返す別のメソッドを使用するメモリ内クエリを要求するのは難しいようです。

しかし、私が言ったように、それは教育的な推測です。うまくいけば、実際にこの設計に取り組んで誰かがチャイムかもしれません。

+1

昨日、私は 'Enumerable.cs'の' LongCount'実装に達するまでこれに答えようとしていました。開始から終了までのシーケンスを単純に列挙します。私は 'IEnumerable 'の実装が 'ICollection 'で、 'Count'で遊んでいるのか、誰が何を知っているのかを調べるようなものを見つけるつもりだと思った。 –

+0

ネットワークストリームに裏付けされた何らかの種類の列挙型について話していても、その日の終わりに「LongCount」が1つずつ進み、* long count *をチェックします。 –

+0

@MatíasFidemraizer:それは間違っています。 Eric Lippertの膨大なデータベーステーブルの例を拡張する:データベースのカウントをクエリすることは、索引やメタデータを使用してサブライン時間で計算することを頻繁に避けます。より少ないデータベース指向の例は、重複を含むソートされたランダムアクセスリストです。わずかに変更されたバイナリサーチを実行することによって、O(logn)時間内にカウントを取得することができる。データベースは、インデックスに基づいて同様の最適化を実行できます。 – Brian

2

しかし私はそれがかもしれないはいくつかを持っている、それが(例えば、それはCOUNT_BIGを生成する必要はなく、SQL ServerのクエリのCOUNT)データベースクエリのために導入されたかなり確信しています別の状況で使用する。たとえば、そのような方法があるとします。

private static Random _r = new Random(1); 
public static IEnumerable<BigInteger> RandomSequence(int upTo) 
{ 
    while (true) { 
     var next = _r.Next(); 
     if (next > upTo) 
      yield break; 
     yield return next; 
    } 
} 

このシーケンスはどのアレイでも焼き付けられず、どこにでも値を格納しません。このように、それは簡単に2B以上のアイテムを生成することができます。ここで、int.MaxValue - 5より大きい数値を生成するために必要な反復回数を確認したいとします。私はこれを行う場合は、次の(Countは便利な内部checked地域で増加をラップしているため)

RandomSequence(int.MaxValue - 5).Count(); 

これは、オーバーフロー例外で失敗します。しかし、レスキューにLongCount!今、私は最終的に種子1、Random.Nextが生成されますとすると、int.MaxValue - 5 2583066202での反復よりも大きくなることを考え出し

RandomSequence(int.MaxValue - 5).LongCount(); 

はい、やや厄介ですが、それでもなおです。

関連する問題