8

我的代码需要知道集合不应为空或仅包含一项。

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

bool collectionHasAtLeast2Items = collection.AtLeast(2);

我可以轻松编写扩展,枚举集合并递增索引器,直到达到请求的大小或用完元素,但是 LINQ 框架中是否已经存在可以执行此操作的内容?我的想法(按我想到的顺序)是:

bool collectionHasAtLeast2Items = collection.Take(2).Count() == 2;或者

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

这似乎可行,尽管没有定义(在文档中)Enumerable.Take Method,但它似乎符合人们的预期。

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

这并不漂亮,因为我总是要做出两个断言,首先是“x”,然后检查我是否真的收到了“x”,这取决于未记录的行为。

或者我可以使用:

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

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

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

或者也许Skip(2).Any(),在语义上也不完全明显,但比 更好ElementAtOrDefault(2) != null,尽管我认为它们会产生相同的结果?

有什么想法吗?

4

3 回答 3

4

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


在幕后,Enumerable.Count()扩展方法检查循环执行下的序列ICollection。如果确实如此,则Count返回属性,因此目标性能应该是 O(1)。

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

于 2012-05-14T12:16:47.917 回答
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;
    }
}
于 2012-05-14T12:31:16.910 回答
3

您可以使用Count,但如果性能是一个问题,使用 . 会更好Take

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

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

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

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.

于 2012-05-14T12:27:48.877 回答