C# Enumerable.Count()的替代项==n
我正在为C# Enumerable.Count()的替代项==n,c#,linq,count,enumerable,C#,Linq,Count,Enumerable,我正在为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 An
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));
}
}
静态类EnumerableExtensions
{
公共静态布尔CountEquals(此IEnumerable items,int n)
{
如果(n使用Enumerable.Count
会比上面的代码好得多。它已经在内部为ICollection
进行了优化
也就是说,如果您必须保留扩展,您可以稍微简化循环:
int count = 0;
foreach (var item in items)
{
count++;
if(count > n)
return false;
}
return count == n;
您可以结合使用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;
}
public static bool CountEquals(此IEnumerable items,int n)
{
var iCollection=作为System.Collections.iCollection的项目;
如果(iCollection!=null)
返回iCollection.Count==n;
返回项目。获取(n+1)。计数()==n;
}
你所说的“更好”到底是什么意思?更快?更容易
从本质上讲,您似乎已经编写了一个专门的方法,该方法针对一个特定的任务进行了优化。您提到了对其进行泛化,但它的性能优势来自于它如此具体的事实(假设有性能优势——像Count
这样的方法已经很难进行性能调优了,而且编译器在优化这样的东西方面也很在行)
如果此特定操作的性能非常重要,值得替换二十个字符的表达式xyz.Count()==abc
有几十行代码,您可能想尝试其他提高性能的方法,如重构。在大多数情况下,使用托管代码的开销将使您获得的性能奖金(如果有的话)相形见绌
也就是说,如果你有大约1000万件物品,而你的目标数量要少得多,我很确定下面的内容会缩短迭代的时间:
int count = 0;
var subset = items.TakeWhile(x => count++ < n + 1);
return count == n + 1;
int count=0;
var子集=items.TakeWhile(x=>count++
易于阅读,易于维护,速度可能也一样快。您意识到可枚举.Count
已经将列表
(实际上是任何集合
)作为特例进行处理,并使用(var e=items.GetEnumerator()){for(int i=0;iCount
属性,对吗如果(!e.MoveNext())返回false;返回!e.MoveNext();}@Dan:True-但是,如果您的“n”很小,我个人会使用集合。Take(n+1).Count()==n
退出短路…@Reed丑陋但可以工作:尝试{l.ElementAt(n)}catch(ArgumentOutOfRangeException ex){@Magnus:这是可行的,但我尽量避免对流控制使用异常处理。@Magnus只确认序列长度的下限为n
,而不是上限。值得一试。我仍然认为编译器可能能够优化xyz.Count()==n
,但如果没有,您可以尝试Stephen Cleary的代码。但是,这仍然(有效地)在Take()和Count()中执行循环。是的,循环仍然存在;我发布的内容与Reed的答案(或者Mehrdad的答案,真的)相当。