使用LINQ检查列表是否为空

Mat*_*ton 122 .net c# linq list

什么是"最佳"(考虑到速度和可读性)的方式来确定列表是否为空?即使列表是类型IEnumerable<T>且没有Count属性.

现在我在这之间折腾:

if (myList.Count() == 0) { ... }
Run Code Online (Sandbox Code Playgroud)

还有这个:

if (!myList.Any()) { ... }
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

    return !list.Any();
}
Run Code Online (Sandbox Code Playgroud)

ang*_*son 100

你可以这样做:

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

编辑:请注意,如果底层源实际上具有快速Count属性,那么简单地使用.Count方法将会很快.上面的有效优化是检测一些基类型并简单地使用它们的.Count属性,而不是.Any()方法,但如果不能保证,则回退到.Any().

  • 或者使用一行并返回(source == null)?true:!source.Any(); (如果你没有抛出异常) (4认同)
  • 我会说,是的,为 null 抛出异常,然后添加第二个名为“IsNullOrEmpty()”的扩展方法。 (2认同)
  • @Gage 如今:`return !source?.Any() ?? 真实;` (2认同)

Dan*_*Tao 14

我会对你似乎已经确定的代码做一个小的补充:同时检查ICollection,因为这甚至是由一些非过时的泛型类(即,Queue<T>Stack<T>)实现的.我也会使用as而不是is因为它更惯用,并且已被证明更快.

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();
}
Run Code Online (Sandbox Code Playgroud)


Kon*_*lph 8

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

这让你感到惊讶吗?我想,对于IList实现,Count只需直接读取元素的数量,同时Any必须查询IEnumerable.GetEnumerator方法,创建实例并MoveNext至少调用一次.

/编辑@Matt:

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

是的,当然可以.这就是我的意思.实际上,它使用ICollection而不是IList结果是相同的.


cru*_*ble 6

我刚写了一个快速测试,试试这个:

 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();
Run Code Online (Sandbox Code Playgroud)

第二个差不多慢三倍:)

再次使用堆栈或数组或其他场景尝试秒表测试,它实际上取决于它看起来的列表类型 - 因为它们证明Count更慢.

所以我想这取决于你正在使用的列表类型!

(只是要指出,我在列表中放置了2000多个对象,计数仍然更快,与其他类型相反)

  • `Enumerable.Count <T>()`对`ICollection <T>`有特殊处理.如果您尝试使用*基本列表以外的其他*,我希望您会看到*显着*不同(较慢)的结果.但是,任何()`都将保持不变. (12认同)
  • 我必须同意马克; 这不是一个真正公平的考验. (2认同)

Das*_*tor 6

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

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

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