Excel 处理时间不是指数线性的吗?(VBA系列)

Excel 处理时间不是指数线性的吗?(VBA系列),excel,collections,vba,Excel,Collections,Vba,在下面的代码示例中,如果我将集合的大小从10000更改为20000,我希望处理时间会延长一倍。相反,当我进行此更改时,处理时间大约是4倍长。字典似乎也有这种指数行为,但数组没有 有人知道这是为什么吗 Sub testing() Dim i As Long Dim coll As New Collection Dim startTime As Single For i = 1 To 10000 'change this value to 20000 to see nonlinear in

在下面的代码示例中,如果我将集合的大小从10000更改为20000,我希望处理时间会延长一倍。相反,当我进行此更改时,处理时间大约是4倍长。字典似乎也有这种指数行为,但数组没有

有人知道这是为什么吗

Sub testing()
Dim i As Long
Dim coll As New Collection
Dim startTime As Single

    For i = 1 To 10000 'change this value to 20000 to see nonlinear increase in processing time
        coll.Add i
    Next i

    startTime = Timer 'start the clock

    For i = 1 To coll.Count
        If coll(i) = 1 Then 'do nothing
        End If
    Next i

    MsgBox "Your final time is " & Round(Timer - startTime, 3)
End Sub

回答这个问题时,我几乎觉得自己是个骗子,因为我是一个自学成才的人,虽然我很想上计算机科学课,但事实是我对记忆分配和检索机制的知识很差

我经常想知道
索引
检索
集合
项目的速度有什么不同,希望一个受过教育的人也能根据我自己的知识回答这个问题

然而,OP要求我将我的评论转换为答案,所以我很乐意接受

我对
集合
对象的经验是,使用
ForEach
循环进行迭代在时间上是线性的,即20000条记录需要10000条的两倍,而使用
For
循环进行迭代是指数的,即20000条记录需要10000条的4倍

所以,对于一个大的收藏来说,这个

Dim v as Variant 'assuming contents of collection is a primitive data type.
For Each v In someCollection
    'process v in some way
Next
会比这快很多

Dim i as Long
For i = 1 to someCollection.Count
    'process someCollection(i) in some way
Next
这有点违反直觉,正如我在几个地方读到的那样,每个循环的
比“For”循环慢大约10%

我完全没有受过教育的结论是,
集合
对象从一开始就循环遍历其成员,以找到指定的索引,这可以解释时间是如何随着集合变得越大而呈指数增长的。这有点道理,特别是与数组相比,因为
集合
对象的结构不是基于顺序的,而对于数组,每个索引实际上是一个内存指针

但是这个怎么样

Dim i as Long
For i = 1 to someCollection.Count
    'process someCollection(Cstr(i)) in some way
Next
检索时间再次变为线性。换句话说,通过键检索成员的速度似乎与数组的速度相似。我想人们一定比我聪明得多,他们开发了某种形式的真正快速的键/内存指针映射,所以不需要对集合进行迭代。正如@bmende所指出的,它可以解释为什么添加带有键的项比不添加键的项花费的时间更长(尽管
字典
添加似乎没有达到这样的程度)

如果人们可以原谅我在披露我处理
收藏
对象的个人规则时的放肆,那么它们就是:

  • 对于每个
  • 循环,仅使用
    进行迭代
    
  • 如果没有键,则将索引转换为字符串并使用该字符串(但要小心删除成员,因为索引字符串现在将被删除)
  • 尽可能避免通过索引引用成员
  • 如果在填充后,
    集合
    不会有太大变化,那么,我将创建一个类,将
    索引
    作为两个属性,并将该类的一个实例添加到集合中,而不是只添加项。这样,我仍然可以对每个
  • 循环使用
    ,并在需要时检索索引值
    像这样:

    Dim member as cMemberItem
    Dim i as Long
    For Each member in someCollection
        i = member.Index
    Next
    
  • 如果我知道我需要在集合中计算成员的基本数据类型,那么我再次使用一个类。例如,要使项(3)的值为value+1,我必须将该值存储在一个temp变量中,删除该项,然后在同一位置添加一个包含修改后的temp值的新项。如果更改每个成员的值,这可能会成为噩梦
  • 而更容易处理的是:

    Dim member as cMemberItem
    For Each member in someCollections
        member.Item = member.Item + 1
    Next
    

    我也注意到了这一点,但如果对每个循环运行
    ,时间是线性的。对coll中的每个v尝试
    Dim v as Variant
    |
    |
    下一步
    ,你就会明白我的意思了。我未受过教育的结论是,处理器循环遍历每个项目以查找索引,而不是数组,其索引实际上是内存指针。哇,请作为答案发布,以便我可以检查它。这大大加快了我的代码速度。我发现按键引用对象与按索引引用对象时也有相同的行为。键引用所花费的时间似乎是线性的,而索引引用所花费的时间是指数的。问题似乎在于,在集合中添加具有键的对象似乎比不使用键参数花费的时间要长得多,但将具有键的对象添加到coll的过程几乎完全是线性的。因此,对于大型集合,我认为按键引用可能比按索引引用快得多,您可以只使用数组……我刚刚将我的注释转换为答案。