是否有LINQ扩展或(一组合理/有效的LINQ扩展)确定集合是否至少具有’x’元素?

我有代码需要知道集合不应该为空或只包含一个项目。

一般来说,我想要一个表单的扩展:

bool collectionHasAtLeast2Items = collection.AtLeast(2);

我可以轻松地编写扩展,枚举集合并递增索引器,直到我达到所请求的大小,或者耗尽元素,但是LINQ框架中是否已经存在这样做? 我的想法(按照我发现的顺序)是::

bool collectionHasAtLeast2Items = collection.Take(2).Count() == 2; 要么

bool collectionHasAtLeast2Items = collection.Take(2).ToList().Count == 2;

虽然采用了比集合包含更多元素的行为没有定义(在文档中) Enumerable.Take方法 ,但它似乎做了人们所期望的。

它不是最有效的解决方案,要么枚举一次取元素,再枚举再次计算它们,这是不必要的,或者枚举一次取元素,然后构造一个列表以获得不是枚举器的count属性-y,因为我实际上不想要列表。

它并不漂亮,因为我总是要做两个断言,首先取’x’,然后检查我实际收到’x’,这取决于无证件的行为。

或许我可以使用:

bool collectionHasAtLeast2Items = collection.ElementAtOrDefault(2) != null;

但是,这在语义上并不明确。 也许最好的方法是使用方法名称来包装它,这意味着我想要的东西。 我假设这将是有效的,我没有反映在代码上。

其他一些想法正在使用Last() ,但我明确地不想枚举整个集合。

或者Skip(2).Any() ,再次在语义上并不完全明显,但优于ElementAtOrDefault(2) != null ,虽然我认为它们会产生相同的结果?

有什么想法吗?

 public static bool AtLeast(this IEnumerable source, int count) { // Optimization for ICollection var genericCollection = source as ICollection; if (genericCollection != null) return genericCollection.Count >= count; // Optimization for ICollection var collection = source as ICollection; if (collection != null) return collection.Count >= count; // General case using (var en = source.GetEnumerator()) { int n = 0; while (n < count && en.MoveNext()) n++; return n == count; } } 

你可以使用Count() >= 2 ,如果你的序列实现ICollection


在场景后面, Enumerable.Count()扩展方法检查循环下的序列是否实现了ICollection 。 如果确实如此,则返回Count属性,因此目标性能应为O(1)。

因此((IEnumerable)((ICollection)sequence)).Count() >= x也应该有O(1)。

您可以使用Count ,但如果性能有问题,那么Take会更好。

 bool atLeastX = collection.Take(x).Count() == x; 

由于Take (我相信)使用延迟执行,它只会经历一次收集。

abatishchev提到Count是O(1)与ICollection ,所以你可以做这样的事情,并获得两全其美。

 IEnumerable col; // set col int x; // set x bool atLeastX; if (col is ICollection) { atLeastX = col.Count() >= x; } else { atLeastX = col.Take(x).Count() == x; } 

你也可以使用Skip/Any ,事实上我敢打赌它会比Take/Count更快。