Where().Count() vs. Count()



这是我的类中继承自List(Of T)的相关部分的摘录。看看SelectedObjectsSelectedCount属性。出于性能原因,我添加了SelectedCount,但现在想知道它是否比SelectedObjects.Count()更好。

Public Class DrawingObjectsList
Inherits List(Of DrawingObjectBase)
Friend ReadOnly Property DOsOfCurrentFace As IEnumerable(Of DrawingObjectBase)
Get
Return Me.Where(Function(DObj) DObj.Face = mFace)
End Get
End Property
Public ReadOnly Property SelectedObjects() As IEnumerable(Of DrawingObjectBase)
Get
Return DOsOfCurrentFace.Where(Function(DObj) DObj.IsSelected = True)
End Get
End Property
Public ReadOnly Property SelectedCount() As Integer
Get
Return DOsOfCurrentFace.Count(Function(DObj) DObj.IsSelected = True)
End Get
End Property
End Class

我的理论是,Where(predicate).Count()Count(predicate)都需要迭代列表,因此应该不会有任何相当大的差异。另外,由于我没有对Where()进行任何ToList()ToArray(),我不确定调用Count()是否能够利用内置的Count属性。

那么我应该保留还是移除SelectedCount财产?

正如Jon Skeet在评论中所说,找出答案的最佳方法是测量。 但是,如果您使用SelectedObjects,我会删除CountObjects。原因如下:

  • 如果您的IEnumerable是内存中列表,那么正如您提到的CountObjects将再次浏览原始列表。如果您已经调用了SelectedObjects并且结果位于变量中,则调用Count将只调用列表中的属性,并立即为您提供对象数,而无需再次循环访问它。如果您没有打电话给SelectedObjects那么我认为打电话.Where(...).Count()并不比.Count(...)。不过,这是您应该测试的内容。

  • 如果您IEnumerable是一个IQueryable那么它要么已经实现,在这种情况下没关系,要么 - 如果它没有实现 - 那么我希望对.Where(...).Count()的调用将转换为与.Count(...)相同的SELECT COUNT(*)查询。同样,这是您应该测试的内容。

我用一些(相当幼稚的)代码计时:

Dim r = New Random()
Dim sw As Stopwatch
Dim list = Enumerable.Range(0, 100000000).Select(Function(x) r.Next)
sw = Stopwatch.StartNew()
list.Count(Function(x) x Mod 2 = 0)
Console.WriteLine(sw.ElapsedMilliseconds)
sw = Stopwatch.StartNew()
Dim x = list.Where(Function(x) x Mod 2 = 0).Count()
Console.WriteLine(sw.ElapsedMilliseconds)

我得到的结果是

Count   Where/Count
-------------------
3494    3624
3484    3612
3523    3617
3522    3609
3500    3623
3493    3631
3536    3620
3541    3682
3621    3633
3515    3686   

平均而言,使用Where/Count花费的时间大约延长了 4%(在这种情况下平均多 110 毫秒)。因此,仅执行Count可能会对性能有好处。但是,您需要首先确认这在您的特定方案/环境中成立。查看 Eric Lippert 的 C# 性能基准测试错误,了解如何做到这一点的好提示。

最新更新