我正在为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));
}
}
我可以做得更好吗?有没有办法在比较中更广泛地概括这一点?
答案 0 :(得分:2)
使用Enumerable.Count
会比上面的代码好很多。它已在内部优化ICollection
。
话虽这么说,如果你必须保留你的扩展,你可以稍微简化循环:
int count = 0;
foreach (var item in items)
{
count++;
if(count > n)
return false;
}
return count == n;
答案 1 :(得分:2)
您可以使用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;
}
答案 2 :(得分:0)
“更好”究竟是什么意思?快点?更轻松?
基本上你所做的就是编写一个专门针对一个特定任务进行优化的方法。你提到它的概括,但它的性能优势源于它是如此具体的事实(假设 性能优势 - 像Count
这样的方法已经很难调整性能,并且编译器非常擅长优化这样的东西。)
Premature optimization is the root of all evil.如果这个特定操作的表现如此重要以至于值得用几十行代码替换二十多个字符的表达式xyz.Count() == abc
,你可能想尝试其他增加的方法表现,就像重构一样。在大多数情况下,使用托管代码的开销只会使您获得的性能加值相形见绌(如果有的话)。
话虽如此 - 如果你有1000万件物品,并且你的目标数量少了很多,我很确定下面的内容会使迭代发生短路:
int count = 0;
var subset = items.TakeWhile(x => count++ < n + 1);
return count == n + 1;
易于阅读,易于维护,可能同样快速。