Enumerable.count()== nの代替
-
28-10-2019 - |
質問
より良い代替品を探しています Enumerable.Count() == n
. 。私が思いつくことができた最高のものは次のとおりです。
static class EnumerableExtensions
{
public static bool CountEquals<T>(this IEnumerable<T> items, int n)
{
if (n <= 0) throw new ArgumentOutOfRangeException("n"); // use Any()
var iCollection = items as System.Collections.ICollection;
if (iCollection != null)
return iCollection.Count == n;
int count = 0;
bool? retval = null;
foreach (var item in items)
{
count++;
if (retval.HasValue)
return false;
if (count == n)
retval = true;
}
if (retval.HasValue)
return retval.Value;
return false;
}
}
class Program
{
static void Main(string[] args)
{
var items0 = new List<int>();
var items1 = new List<int>() { 314 };
var items3 = new List<int>() { 1, 2, 3 };
var items5 = new List<int>() { 1, 2, 3, 4, 5 };
var items10 = Enumerable.Range(0, 10);
var itemsLarge = Enumerable.Range(0, Int32.MaxValue);
Console.WriteLine(items0.CountEquals(3));
Console.WriteLine(items1.CountEquals(3));
Console.WriteLine(items3.CountEquals(3));
Console.WriteLine(items5.CountEquals(3));
Console.WriteLine(itemsLarge.CountEquals(3));
}
}
もっと上手くできますか?これをさらに一般化する方法はありますか?
解決
の組み合わせを使用できます Take
と Count
ループを完全に取り除くには:
public static bool CountEquals<T>(this IEnumerable<T> items, int n)
{
var iCollection = items as System.Collections.ICollection;
if (iCollection != null)
return iCollection.Count == n;
return items.Take(n + 1).Count() == n;
}
他のヒント
使用 Enumerable.Count
上記のコードよりもはるかに優れています。すでに最適化しています ICollection
初めの。
そうは言っても、拡張機能を維持する必要がある場合は、ループを少し単純化できます。
int count = 0;
foreach (var item in items)
{
count++;
if(count > n)
return false;
}
return count == n;
正確にはどういう意味ですか "より良い"?もっと早く?より簡単に?
基本的に、あなたがやったと思われることは、特定のタスクに最適化された専門的な方法です。あなたはそれを一般化することについて言及しますが、そのパフォーマンスの利点はそれが非常に具体的であるという事実に起因します(そこに仮定して は パフォーマンスの優位性 - のようなもの Count
すでにパフォーマンスにはかなり難しく調整されており、コンパイラはこのようなものを最適化するのがかなり得意です)。
早期最適化はすべての悪の根源です。 この特定の操作のパフォーマンスが非常に重要であるため、21文字の式を置き換える価値がある場合 xyz.Count() == abc
数十行のコードを使用すると、リファクタリングなど、パフォーマンスを向上させる他の方法を試してみることができます。ほとんどの状況では、マネージドコードを使用することによるオーバーヘッドは、(もしあれば)パフォーマンスボーナスをwar小化します。
そうは言っても - あなたが1,000万のアイテムのようなものを持っていて、あなたのターゲット数がはるかに少ないなら、私は以下が反復を短絡するだろうと確信しています:
int count = 0;
var subset = items.TakeWhile(x => count++ < n + 1);
return count == n + 1;
読みやすく、メンテナンスが簡単で、おそらく同じくらい速いです。