检查IEnumerable是否具有少于一定数量的项目而不会导致任何不必要的评估?

Luk*_*lch 10 c# linq

有时我希望有一定范围的项目,需要进行一些验证以确保我在该范围内.最明显的方法是将集合中的项目数与范围进行比较.

public static bool IsWithinRange<T>(this IEnumerable<T> enumerable, int max)
{
    return enumerable.Count() <= max;
}
Run Code Online (Sandbox Code Playgroud)

虽然,我的理解是linq Count()方法将在返回结果之前评估整个可枚举.理想情况下,我只会对最小数量的项目进行评估以获得我的结果.

在不引起任何不必要评估的情况下,确保可枚举项目少于一定数量的最佳方法是什么?

Jef*_*ado 15

Count()如您所知,不要使用整个集合必须遍历.

你可以这样做:

public static bool IsWithinRange<T>(this IEnumerable<T> enumerable, int max)
{
    return !enumerable.Skip(max).Any();
}
Run Code Online (Sandbox Code Playgroud)

请注意,您仍然需要枚举max集合中的第一个项目,除非您尝试对基础集合做出一些假设,否则这是不可避免的.


要进一步优化这一点,您可以检查基础类型是否为ICollection<>ICollection访问该Count属性.这样您就不必枚举项目了.否则在枚举项目时回退.

public static bool IsWithinRange<T>(this IEnumerable<T> enumerable, int max)
{
    var asCollection = enumerable as System.Collections.ICollection;
    if (asCollection != null) return asCollection.Count <= max;
    var asGenericCollection = enumerable as ICollection<T>;
    if (asGenericCollection != null) return asGenericCollection.Count <= max;
    return !enumerable.Skip(max).Any();
}
Run Code Online (Sandbox Code Playgroud)

当然,这并不是完全免费的,因为你正在进行额外的检查,但是如果可能的话,尤其max是在很大的情况下,它必须在集合上进行枚举.


Cor*_*sak 7

有几种不同的方法可以做到这一点.也许最简单的是:

public static bool IsWithinRange<T>(this IEnumerable<T> enumerable, int max)
{
    return enumerable.Take(max+1).Count() <= max;
}
Run Code Online (Sandbox Code Playgroud)