我的代码需要知道集合不应该为空或只包含一个项目。
一般来说,我想要扩展表单:
bool collectionHasAtLeast2Items = collection.AtLeast(2);
我可以轻松编写扩展,枚举集合并递增索引器,直到达到请求的大小,或者用完元素,但LINQ框架中是否已经存在这样做?我的想法(按照发给我的顺序)是::
bool collectionHasAtLeast2Items = collection.Take(2).Count() == 2;
或
bool collectionHasAtLeast2Items = collection.Take(2).ToList().Count == 2;
这似乎有用,虽然没有定义(在文档中)Enumerable.Take Method 定义了比集合包含更多元素的行为,但是,它似乎做了人们所期望的。
它不是最有效的解决方案,要么枚举一次取元素,再枚举再次计算它们,这是不必要的,或枚举一次取元素,然后构造一个列表以获得count属性是枚举器-y,因为我实际上并不想要列表。
它并不漂亮,因为我总是要做两个断言,首先取'x',然后检查我实际收到的'x',这取决于无证件的行为。
或许我可以使用:
bool collectionHasAtLeast2Items = collection.ElementAtOrDefault(2) != null;
然而,这在语义上并不明确。也许最好的方法是使用方法名称来包装它,这意味着我想要的东西。我假设这将是有效的,我没有反映在代码上。
其他一些想法正在使用Last()
,但我明确地不想枚举整个集合。
或者也许Skip(2).Any()
,再次在语义上并不完全明显,但优于ElementAtOrDefault(2) != null
,虽然我认为它们会产生相同的结果?
有什么想法吗?
答案 0 :(得分:4)
如果您按顺序实现Count() >= 2
?
ICollection
在场景后面,Enumerable.Count()
扩展方法检查循环下的序列是否实现ICollection
。如果确实如此,则返回Count
属性,因此目标性能应为O(1)。
因此((IEnumerable<T>)((ICollection)sequence)).Count() >= x
也应该有O(1)。
答案 1 :(得分:4)
public static bool AtLeast<T>(this IEnumerable<T> source, int count)
{
// Optimization for ICollection<T>
var genericCollection = source as ICollection<T>;
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;
}
}
答案 2 :(得分:3)
您可以使用Count
,但如果性能有问题,那么Take
会更好。
bool atLeastX = collection.Take(x).Count() == x;
由于Take
(我相信)使用延迟执行,因此它只会经过一次收集。
abatishchev提到Count
与ICollection
是O(1),所以你可以做这样的事情并充分利用这两个世界。
IEnumerable<int> col;
// set col
int x;
// set x
bool atLeastX;
if (col is ICollection<int>)
{
atLeastX = col.Count() >= x;
}
else
{
atLeastX = col.Take(x).Count() == x;
}
你也可以使用Skip/Any
,事实上我敢打赌它会比Take/Count
更快。