假设我们有一个Class1的通用列表,通常有给定会话的约100个对象。 我想看看列表是否有特定的对象。 ASP.NET 2.0允许我这样做:
Dim objResult as Class1 = objList.Find(objSearch)
与传统的For循环相比,从性能角度来看,这种方法的速度如何?
这会随着列表长度的增加或减少而变化吗?
答案 0 :(得分:7)
它与循环完全相同 - 这就是它在内部的作用。
如果您的列表已排序并且您正在寻找特定值,则可能会使用BinarySearch
- 但如果您考虑它,如果您对谓词或顺序没有任何了解数据,它 来查看每个项目,直到找到匹配项。碰巧的是,Find
被指定为返回列表中的 first 项...所以它只是以明显的顺序查看。
这将与列表的大小成线性关系 - 即,平均而言,搜索10倍大的列表将花费10倍的时间。当然,这取决于是否以及找到匹配的地方;如果第一个项目在每种情况下匹配,无论列表有多大,它都会在同一时间完成:)
老实说,只有100个物体,听起来不太可能成为瓶颈。
答案 1 :(得分:3)
您可以轻松查看.Net List
如何使用Reflector实现Find
方法:
Public Function Find(ByVal match As Predicate(Of T)) As T
If (match Is Nothing) Then
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match)
End If
Dim i As Integer
For i = 0 To Me._size - 1
If match.Invoke(Me._items(i)) Then
Return Me._items(i)
End If
Next i
Return CType(Nothing, T)
End Function
两种实现之间的唯一区别是Find
需要调用match
而不是在循环中内联此逻辑。
有趣的是,这个简单的表现:
var persons = new List<Person>();
for (int i = 0; i < 100; i++)
{
persons.Add(new Person { ID = i });
}
GC.Collect();
var sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
persons.Find(person => person.ID == i % 100);
}
sw.Stop();
Console.WriteLine(sw.Elapsed);
GC.Collect();
sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
for (int j = 0; j < 100; j++)
{
if (persons[j].ID == i % 100)
{
break;
}
}
}
sw.Stop();
Console.WriteLine(sw.Elapsed);
显示:
使用 查找查询列表所需的总时间为05.7990078 秒。
使用 循环查询列表所需的总时间为06.3551074 秒。
这个结果在几次执行中似乎是一致的。
修改 - 找到Find
优势的解释:
Find
工作得更快,因为它在每次迭代中直接访问底层数组。循环通过List
索引器访问它,这需要每个访问索引验证:
Public Default Property Item(ByVal index As Integer) As T
Get
If (index >= Me._size) Then
ThrowHelper.ThrowArgumentOutOfRangeException
End If
Return Me._items(index) // _items is the underlying array.
End Get