检查LINQ列表是否为空

什么是“最好的”(考虑到速度和可读性),以确定列表是否为空? 即使列表的types是IEnumerable<T>并且没有Count属性。

现在我在这之间折腾:

 if (myList.Count() == 0) { ... } 

和这个:

 if (!myList.Any()) { ... } 

我的猜测是,第二个选项更快,因为一旦它看到第一个项目就会返回结果,而第二个选项(对于IEnumerable)将需要访问每个项目以返回计数。

话虽如此,第二个选项看起来对你来说是可读的吗? 你更喜欢哪个? 或者你能想出一个更好的方法来testing一个空的列表吗?

编辑 @ lassevk的回应似乎是最合乎逻辑的,再加上一些运行时检查,如果可能,使用caching计数,如下所示:

 public static bool IsEmpty<T>(this IEnumerable<T> list) { if (list is ICollection<T>) return ((ICollection<T>)list).Count == 0; return !list.Any(); } 

你可以这样做:

 public static Boolean IsEmpty<T>(this IEnumerable<T> source) { if (source == null) return true; // or throw an exception return !source.Any(); } 

编辑 :请注意,简单地使用.Count方法将是快速的,如果底层的源实际上有一个快速的计数属性。 上面的一个有效的优化是检测一些基types,并简单地使用这些属性的.Count属性,而不是.Any()方法,但如果不能保证可以返回.Any()。

我将对你似乎已经解决的代码做一个小小的补充:还要检查ICollection ,因为即使是一些非过时的generics类(也就是Queue<T>Stack<T> ),也Stack<T> 。 我也会用as来代替,因为它比较习惯,而且显示速度更快 。

 public static bool IsEmpty<T>(this IEnumerable<T> list) { if (list == null) { throw new ArgumentNullException("list"); } var genericCollection = list as ICollection<T>; if (genericCollection != null) { return genericCollection.Count == 0; } var nonGenericCollection = list as ICollection; if (nonGenericCollection != null) { return nonGenericCollection.Count == 0; } return !list.Any(); } 

LINQ本身必须以某种方式围绕Count()方法进行一些严格的优化。

这令你感到惊讶吗? 我认为对于IList实现, Count直接读取元素的数量,而Any必须查询IEnumerable.GetEnumerator方法,创build一个实例并至lessMoveNext一次MoveNext

/编辑@Matt:

我只能假设IEnumerable的Count()扩展方法是这样的:

是的,当然是的。 这就是我的意思。 实际上,它使用ICollection而不是IList但结果是一样的。

我只是写了一个快速testing,试试这个:

  IEnumerable<Object> myList = new List<Object>(); Stopwatch watch = new Stopwatch(); int x; watch.Start(); for (var i = 0; i <= 1000000; i++) { if (myList.Count() == 0) x = i; } watch.Stop(); Stopwatch watch2 = new Stopwatch(); watch2.Start(); for (var i = 0; i <= 1000000; i++) { if (!myList.Any()) x = i; } watch2.Stop(); Console.WriteLine("myList.Count() = " + watch.ElapsedMilliseconds.ToString()); Console.WriteLine("myList.Any() = " + watch2.ElapsedMilliseconds.ToString()); Console.ReadLine(); 

第二个几乎慢了三倍:)

再次尝试使用Stack或数组或其他场景的秒表testing,它实际上取决于列表的types,因为它们certificateCount更慢。

所以我想这取决于你使用的列表types!

(只要指出,我把2000+对象放在列表中,而且计数仍然更快,与其他types相反)

@Konrad令我感到惊讶的是,在我的testing中,我将列表传递给接受IEnumerable<T> ,所以运行时无法通过调用IList<T>的Count()扩展方法来优化它。

我只能假设IEnumerable的Count()扩展方法是这样的:

 public static int Count<T>(this IEnumerable<T> list) { if (list is IList<T>) return ((IList<T>)list).Count; int i = 0; foreach (var t in list) i++; return i; } 

换句话说,针对IList<T>的特殊情况进行了一些运行时优化。

/编辑@Konrad +1队友 – 你说得对,更可能是ICollection<T>

根据微软的文档, List.Count是O(1):
http://msdn.microsoft.com/en-us/library/27b47ht3.aspx

所以只需使用List.Count == 0它比查询快得多

这是因为它有一个名为Count的数据成员,在任何时候添加或从列表中删除了某个数据成员,所以当你调用List.Count它不必遍历每个元素来获取它,它只是返回数据会员。

如果您有多个项目,第二个选项会更快。

  • Any()返回一个项目被find。
  • Count()必须继续遍历整个列表。

例如,假设枚举有1000个项目。

  • Any()会检查第一个,然后返回true。
  • 在遍历整个枚举之后Count()将返回1000。

如果使用其中一个谓词覆盖,则这可能会更糟 – Count()仍然需要检查每个单个项目,即使只有一个匹配项。

你习惯于使用任何一个 – 它是有道理的,是可读的。

一个警告 – 如果你有一个列表,而不只是一个IEnumerable然后使用该列表的计数属性。

好的,那这个怎么样?

 public static bool IsEmpty<T>(this IEnumerable<T> enumerable) { return !enumerable.GetEnumerator().MoveNext(); } 

编辑:我刚刚意识到有人已经草拟了这个解决scheme已经。 有人提到Any()方法会做到这一点,但为什么不自己做? 问候

另一个想法:

 if(enumerable.FirstOrDefault() != null) 

不过,我更喜欢Any()方法。

这对于使用Entity Framework来说非常重要:

 var genericCollection = list as ICollection<T>; if (genericCollection != null) { //your code } 

如果我用Count()检查Linq在数据库中执行“SELECT COUNT(*)..”,但是我需要检查结果是否包含数据,我决定引入FirstOrDefault()而不是Count()。

之前

 var cfop = from tabelaCFOPs in ERPDAOManager.GetTable<TabelaCFOPs>() if (cfop.Count() > 0) { var itemCfop = cfop.First(); //.... } 

 var cfop = from tabelaCFOPs in ERPDAOManager.GetTable<TabelaCFOPs>() var itemCfop = cfop.FirstOrDefault(); if (itemCfop != null) { //.... } 
 private bool NullTest<T>(T[] list, string attribute) { bool status = false; if (list != null) { int flag = 0; var property = GetProperty(list.FirstOrDefault(), attribute); foreach (T obj in list) { if (property.GetValue(obj, null) == null) flag++; } status = flag == 0 ? true : false; } return status; } public PropertyInfo GetProperty<T>(T obj, string str) { Expression<Func<T, string, PropertyInfo>> GetProperty = (TypeObj, Column) => TypeObj.GetType().GetProperty(TypeObj .GetType().GetProperties().ToList() .Find(property => property.Name .ToLower() == Column .ToLower()).Name.ToString()); return GetProperty.Compile()(obj, str); } 
 List<T> li = new List<T>(); (li.First().DefaultValue.HasValue) ? string.Format("{0:yyyy/MM/dd}", sender.First().DefaultValue.Value) : string.Empty; 

这是我对丹涛答案的实现,允许一个谓词:

 public static bool IsEmpty<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) throw new ArgumentNullException(); if (IsCollectionAndEmpty(source)) return true; return !source.Any(predicate); } public static bool IsEmpty<TSource>(this IEnumerable<TSource> source) { if (source == null) throw new ArgumentNullException(); if (IsCollectionAndEmpty(source)) return true; return !source.Any(); } private static bool IsCollectionAndEmpty<TSource>(IEnumerable<TSource> source) { var genericCollection = source as ICollection<TSource>; if (genericCollection != null) return genericCollection.Count == 0; var nonGenericCollection = source as ICollection; if (nonGenericCollection != null) return nonGenericCollection.Count == 0; return false; } 

myList.ToList().Count == 0 。 就这样

这个扩展方法适用于我:

 public static bool IsEmpty<T>(this IEnumerable<T> enumerable) { try { enumerable.First(); return false; } catch (InvalidOperationException) { return true; } }