什么是“最佳”(考虑到速度和可读性)的方式来确定列表是否为空?即使列表的类型为IEnumerable<T>
且没有Count属性。
现在我在这之间折腾:
if (myList.Count() == 0) { ... }
和此:
if (!myList.Any()) { ... }
我的猜测是第二个选项更快,因为它会在看到第一个项目后立即返回结果,而第二个选项(对于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();
}
答案 0 :(得分:99)
你可以这样做:
public static Boolean IsEmpty<T>(this IEnumerable<T> source)
{
if (source == null)
return true; // or throw an exception
return !source.Any();
}
编辑:请注意,如果底层源实际上具有快速Count属性,那么简单地使用.Count方法将会很快。上面的有效优化是检测一些基类型并简单地使用它们的.Count属性,而不是.Any()方法,但如果不能保证,则回退到.Any()。
答案 1 :(得分:14)
我会对你似乎已经确定的代码做一个小的补充:同时检查ICollection
,因为这也是由一些非过时的泛型类实现的(即Queue<T>
和Stack<T>
)。我还会使用as
代替is
,因为它更具惯用性和has been shown to be faster。
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();
}
答案 2 :(得分:8)
LINQ本身必须以某种方式围绕Count()方法做一些严肃的优化。
这会让你感到惊讶吗?我想,对于IList
实现,Count
只是直接读取元素的数量而Any
必须查询IEnumerable.GetEnumerator
方法,创建实例并调用MoveNext
至少一次。
/编辑@Matt:
我只能假设IEnumerable的Count()扩展方法是这样的:
是的,当然可以。这就是我的意思。实际上,它使用的是ICollection
而不是IList
,但结果是相同的。
答案 3 :(得分: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();
第二种情况几乎慢了三倍:)
使用堆栈或数组或其他方案再次尝试秒表测试,它实际上取决于它看起来的列表类型 - 因为它们证明Count更慢。
所以我想这取决于你正在使用的列表类型!
(只是要指出,我在列表中放置了2000多个对象,计数仍然更快,与其他类型相反)
答案 4 :(得分:4)
List.Count
是O(1):
http://msdn.microsoft.com/en-us/library/27b47ht3.aspx
所以只需使用List.Count == 0
它比查询
这是因为它有一个名为Count的数据成员,只要在列表中添加或删除某些内容就会更新,因此当您调用List.Count
时,它不必遍历每个元素来获取它,它只返回数据成员。
答案 5 :(得分:3)
如果您有多个项目,第二个选项要快得多。
Any()
就会返回。Count()
必须继续浏览整个列表。例如,假设枚举有1000个项目。
Any()
会检查第一个,然后返回true。Count()
将返回1000。如果使用其中一个谓词覆盖,这可能会更糟糕 - Count()仍然必须检查每个项目,即使它只有一个匹配项。
你习惯使用任何一个 - 它确实有意义且可读。
一个警告 - 如果您有一个List,而不仅仅是一个IEnumerable,那么请使用该列表的Count属性。
答案 6 :(得分:3)
@Konrad让我感到惊讶的是,在我的测试中,我将列表传递给接受IEnumerable<T>
的方法,因此运行时无法通过调用{{的Count()扩展方法来优化它。 1}}。
我只能假设IEnumerable的Count()扩展方法是这样的:
IList<T>
...换句话说,针对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;
}
的特殊情况进行了一些运行时优化。
/编辑@Konrad +1伙伴 - 你说的更可能是IList<T>
。
答案 7 :(得分:1)
好的,那这个怎么样?
public static bool IsEmpty<T>(this IEnumerable<T> enumerable)
{
return !enumerable.GetEnumerator().MoveNext();
}
编辑:我刚刚意识到有人已经草拟了这个解决方案。有人提到Any()方法会这样做,但为什么不自己做呢?此致
答案 8 :(得分:1)
另一个想法:
if(enumerable.FirstOrDefault() != null)
但我更喜欢Any()方法。
答案 9 :(得分:1)
这对于使其与Entity Framework一起使用至关重要:
var genericCollection = list as ICollection<T>;
if (genericCollection != null)
{
//your code
}
答案 10 :(得分:0)
如果我用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)
{
//....
}
答案 11 :(得分:0)
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);
}
答案 12 :(得分:0)
这是我对Dan Tao的回答的实现,允许谓词:
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;
}
答案 13 :(得分:-1)
List<T> li = new List<T>();
(li.First().DefaultValue.HasValue) ? string.Format("{0:yyyy/MM/dd}", sender.First().DefaultValue.Value) : string.Empty;
答案 14 :(得分:-3)
myList.ToList().Count == 0
。那就是
答案 15 :(得分:-5)
此扩展方法适用于我:
public static bool IsEmpty<T>(this IEnumerable<T> enumerable)
{
try
{
enumerable.First();
return false;
}
catch (InvalidOperationException)
{
return true;
}
}