C# 使用 LINQ 检查列表是否为空
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/41319/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Checking if a list is empty with LINQ
提问by Matt Hamilton
What's the "best" (taking both speed and readability into account) way to determine if a list is empty? Even if the list is of type IEnumerable<T>
and doesn't have a Count property.
确定列表是否为空的“最佳”(同时考虑速度和可读性)方法是什么?即使列表属于类型IEnumerable<T>
并且没有 Count 属性。
Right now I'm tossing up between this:
现在我在这之间折腾:
if (myList.Count() == 0) { ... }
and this:
和这个:
if (!myList.Any()) { ... }
My guess is that the second option is faster, since it'll come back with a result as soon as it sees the first item, whereas the second option (for an IEnumerable) will need to visit every item to return the count.
我的猜测是第二个选项更快,因为它会在看到第一个项目后立即返回结果,而第二个选项(对于 IEnumerable)将需要访问每个项目以返回计数。
That being said, does the second option look as readable to you? Which would you prefer? Or can you think of a better way to test for an empty list?
话虽如此,第二个选项对您来说是否可读?你更喜欢哪个?或者你能想到一个更好的方法来测试一个空列表吗?
Edit@lassevk's response seems to be the most logical, coupled with a bit of runtime checking to use a cached count if possible, like this:
编辑@lassevk 的响应似乎是最合乎逻辑的,再加上一些运行时检查以在可能的情况下使用缓存计数,如下所示:
public static bool IsEmpty<T>(this IEnumerable<T> list)
{
if (list is ICollection<T>) return ((ICollection<T>)list).Count == 0;
return !list.Any();
}
采纳答案by Lasse V. Karlsen
You could do this:
你可以这样做:
public static Boolean IsEmpty<T>(this IEnumerable<T> source)
{
if (source == null)
return true; // or throw an exception
return !source.Any();
}
Edit: Note that simply using the .Count method will be fast if the underlying source actually has a fast Count property. A valid optimization above would be to detect a few base types and simply use the .Count property of those, instead of the .Any() approach, but then fall back to .Any() if no guarantee can be made.
编辑:请注意,如果基础源实际上具有快速 Count 属性,则仅使用 .Count 方法会很快。上面的一个有效优化是检测一些基本类型并简单地使用它们的 .Count 属性,而不是 .Any() 方法,但如果不能保证,则回退到 .Any() 。
回答by crucible
I just wrote up a quick test, try this:
我刚刚写了一个快速测试,试试这个:
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();
The second is almost three times slower :)
第二个几乎慢了三倍:)
Trying the stopwatch test again with a Stack or array or other scenarios it really depends on the type of list it seems - because they prove Count to be slower.
使用 Stack 或数组或其他场景再次尝试秒表测试,它实际上取决于它看起来的列表类型 - 因为它们证明 Count 更慢。
So I guess it depends on the type of list you're using!
所以我想这取决于您使用的列表类型!
(Just to point out, I put 2000+ objects in the List and count was still faster, opposite with other types)
(只是指出,我在 List 中放入了 2000+ 个对象,计数仍然更快,与其他类型相反)
回答by Keith
The second option is much quicker if you have multiple items.
如果您有多个项目,则第二个选项要快得多。
Any()
returns as soon as 1 item is found.Count()
has to keep going through the entire list.
Any()
找到 1 个项目后立即返回。Count()
必须继续浏览整个列表。
For instance suppose the enumeration had 1000 items.
例如,假设枚举有 1000 个项目。
Any()
would check the first one, then return true.Count()
would return 1000 after traversing the entire enumeration.
Any()
将检查第一个,然后返回 true。Count()
遍历整个枚举后将返回 1000。
This is potentially worse if you use one of the predicate overrides - Count() still has to check every single item, even it there is only one match.
如果您使用谓词覆盖之一,这可能会更糟 - Count() 仍然必须检查每个项目,即使只有一个匹配项。
You get used to using the Any one - it does make sense and is readable.
您习惯于使用 Any one - 它确实有意义且可读。
One caveat - if you have a List, rather than just an IEnumerable then use that list's Count property.
一个警告 - 如果您有一个列表,而不仅仅是一个 IEnumerable,那么请使用该列表的 Count 属性。
回答by Konrad Rudolph
LINQ itself must be doing some serious optimization around the Count() method somehow.
LINQ 本身必须以某种方式围绕 Count() 方法进行一些认真的优化。
Does this surprise you? I imagine that for IList
implementations, Count
simply reads the number of elements directly while Any
has to query the IEnumerable.GetEnumerator
method, create an instance and call MoveNext
at least once.
这让你感到惊讶吗?我想对于IList
实现,Count
只需直接读取元素的数量,同时Any
必须查询IEnumerable.GetEnumerator
方法、创建实例并MoveNext
至少调用一次。
/EDIT @Matt:
/编辑@马特:
I can only assume that the Count() extension method for IEnumerable is doing something like this:
我只能假设 IEnumerable 的 Count() 扩展方法正在做这样的事情:
Yes, of course it does. This is what I meant. Actually, it uses ICollection
instead of IList
but the result is the same.
是的,当然可以。这就是我的意思。实际上,它使用了ICollection
而不是,IList
但结果是一样的。
回答by Matt Hamilton
@Konrad what surprises me is that in my tests, I'm passing the list into a method that accepts IEnumerable<T>
, so the runtime can't optimize it by calling the Count() extension method for IList<T>
.
@Konrad 让我感到惊讶的是,在我的测试中,我将列表传递给了一个接受 的方法IEnumerable<T>
,因此运行时无法通过调用 Count() 扩展方法来优化它IList<T>
。
I can only assume that the Count() extension method for IEnumerable is doing something like this:
我只能假设 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;
}
... in other words, a bit of runtime optimization for the special case of IList<T>
.
... 换句话说,对IList<T>
.
/EDIT @Konrad +1 mate - you're right about it more likely being on ICollection<T>
.
/EDIT @Konrad +1 队友 - 你说得对,更有可能在ICollection<T>
.
回答by Jonny Dee
This extension method works for me:
这个扩展方法对我有用:
public static bool IsEmpty<T>(this IEnumerable<T> enumerable)
{
try
{
enumerable.First();
return false;
}
catch (InvalidOperationException)
{
return true;
}
}
回答by Jonny Dee
Ok, so what about this one?
好的,那么这个呢?
public static bool IsEmpty<T>(this IEnumerable<T> enumerable)
{
return !enumerable.GetEnumerator().MoveNext();
}
EDIT: I've just realized that someone has sketched this solution already. It was mentioned that the Any() method will do this, but why not do it yourself? Regards
编辑:我刚刚意识到有人已经草拟了这个解决方案。有人提到 Any() 方法会这样做,但为什么不自己做呢?问候
回答by ChulioMartinez
Another idea:
另一个想法:
if(enumerable.FirstOrDefault() != null)
However I like the Any() approach more.
不过我更喜欢 Any() 方法。
回答by Dasmowenator
List.Count
is O(1) according to Microsoft's documentation:
http://msdn.microsoft.com/en-us/library/27b47ht3.aspx
List.Count
根据微软的文档是 O(1):http:
//msdn.microsoft.com/en-us/library/27b47ht3.aspx
so just use List.Count == 0
it's much faster than a query
所以只是使用List.Count == 0
它比查询快得多
This is because it has a data member called Count which is updated any time something is added or removed from the list, so when you call List.Count
it doesn't have to iterate through every element to get it, it just returns the data member.
这是因为它有一个名为 Count 的数据成员,它会在任何时候从列表中添加或删除某些内容时更新,因此当您调用List.Count
它时,不必遍历每个元素来获取它,它只返回数据成员。
回答by Dan Tao
I would make one small addition to the code you seem to have settled on: check also for ICollection
, as this is implemented even by some non-obsolete generic classes as well (i.e., Queue<T>
and Stack<T>
). I would also use as
instead of is
as it's more idiomatic and has been shown to be faster.
我会对您似乎已经确定的代码做一个小的补充:也检查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();
}