私がやりたいこと、短いバージョン:
var source = new[]{2,4,6,1,9}.OrderBy(x=>x);
int count = source.Count; // <-- get the number of elements without performing the sort
長いバージョン:
IEnumerableの要素数を決定するには、すべての要素を反復処理する必要があります。これは、非常にコストのかかる操作になる可能性があります。
IEnumerableをICollectionにキャストできる場合は、反復せずにカウントをすばやく決定できます。LINQ Count() メソッドはこれを自動的に行います。
関数myEnumerable.OrderBy()はIOrderedEnumerableを返します。IOrderedEnumerableは明らかにICollectionにキャストできないため、 Count()を呼び出すとすべてが消費されます。
ただし、並べ替えによって要素の数は変更されず、IOrderedEnumerableはそのソースへの参照を保持する必要があります。したがって、そのソースがICollectionの場合、 IOrderedEnumerableを消費せずにカウントを決定できるはずです。
私の目標は、n 個の要素を持つIEnumerableを取得し、たとえば n/2 の位置にある要素を取得するライブラリ メソッドを作成することです。
カウントを取得するためだけにIEnumerableを 2 回繰り返すことは避けたいのですが、可能であれば不要なコピーを作成することも避けたいと考えています。
これが私が作成したい関数のスケルトンです
public void DoSomething(IEnumerable<T> source)
{
int count; // What we do with the source depends on its length
if (source is ICollection)
{
count = source.Count(); // Great, we can use ICollection.Count
}
else if (source is IOrderedEnumerable)
{
// TODO: Find out whether this is based on an ICollection,
// TODO: then determine the count of that ICollection
}
else
{
// Iterating over the source may be expensive,
// to avoid iterating twice, make a copy of the source
source = source.ToList();
count = source.Count();
}
// do some stuff
}