访问VBA如何从Collection中删除重复

时间:2015-11-12 19:55:43

标签: vba collections access-vba time-complexity

如何删除Collection中的重复对象?这就是我试过的:

    dim unique_students as Collection
    dim no_duplicate_student as cls_Student
    dim no_duplication as boolean

For Each student as cls_Student In list_Student 'list_Students = original unsorted collection

         no_duplication = True

         Dim s As cls_Student
         For Each s In unique_students

            If s.name = student.name  Then 
               no_duplication = False 'Duplication found
               Exit For
            End If

         next s

         If no_duplication Then 
'Inserted into new sorted collection if no values matches that of the sorted collection

           Set no_duplicate_student = New clsOverlap
           no_duplicate_student.name = student.name

           unique_students.Add no_duplicate_student

         End If

Next student

然而,这仍然需要很长时间(if list_Student.Count > 5000,然后运行需要30分钟+)。是否有更有效的方法(如果可能,减少时间复杂度)删除集合中的重复?

2 个答案:

答案 0 :(得分:1)

将学生姓名添加到词典,其中包含.Exists方法,以检查项目是否已存在于词典中。

您可以在Collection And Dictionary Procedures

中的CollectionToDictionary获取一些想法

For Each student循环中的类似内容:

If Dict.Exists(Key:=student.name) Then
    ' is duplicate!
Else
    Dict.Add Key:=student.name, Item:=student.name
    ' you could also do Item:=student if you want the de-duplicated list in a dictionary
End If

不需要内循环。该功能几乎可以瞬间运行。

答案 1 :(得分:1)

我通常使用像Andre451建议的字典。或者你可以像这样使用ArrayList。我不确定两者之间是否存在很大的性能差异,但如果需要,此方法也会生成一个排序列表。字典虽然可以携带键/值对,但它只取决于你要追求的东西。

    <div id="container">
      <img id="image" src="http://www.noao.edu/image_gallery/images/d4/androa.jpg" />
      <p id="text">
        Hello World!
      </p>
    </div>

编辑:经过测试,我确认字典方法的速度大约是7.7秒的两倍,而百万分之13秒。但是,在OP计数为5000时,差异仅为40 vs 80 ms。

在此测试代码......

Error in arima.sim(model = list(ar = c(3, 0, 5)), n = 50) :'ar' part of 
model is not stationary

再次编辑:好的,所以我发现这非常有趣。最重要的似乎是实际类型本身。因此,例如,上面的测试创建了一个ArrayList,从中可以派生出唯一值。如果将其更改为基本整数数组Sub Demo() Set AL = CreateObject("System.Collections.ArrayList") AL.Add "A" AL.Add "B" AL.Add "A" AL.Add "A" AL.Add "C" 'Sorting allows sequential comparisons to determine uniqueness 'You could also do something similar to the dictionary method with ArrayList.Contains 'but the evluation of ArrayList.Contains runs slower than this AL.Sort For i = 0 To AL.Count - 2 If AL(i) <> AL(i + 1) Then 'Prints unique values Debug.Print AL(i) End If Next If AL(i) <> AL(i - 1) Then 'Prints last value if unique by comparing to one before it Debug.Print AL(i) End If End Sub ,则时间从7.7秒减少到0.8秒。同样,只需在排序操作之后添加行Public Declare Function GetTickCount Lib "kernel32.dll" () As Long Sub DictionaryDemo() Set D = CreateObject("Scripting.Dictionary") Set AL = CreateObject("System.Collections.ArrayList") For i = 0 To 10 ^ 6 AL.Add Round(Rnd * 10, 0) Next Start = GetTickCount For i = 0 To AL.Count - 1 If Not (D.Exists(AL(i))) Then D.Add AL(i), "" Debug.Print AL(i) End If Next Debug.Print GetTickCount - Start End Sub Sub ArrayListDemo() Set AL = CreateObject("System.Collections.ArrayList") For i = 0 To 10 ^ 6 AL.Add Round(Rnd * 10, 0) Next 'Sorting allows sequential comparisons to determine uniqueness Start = GetTickCount AL.Sort For i = 0 To AL.Count - 2 If AL(i) <> AL(i + 1) Then 'Prints unique values Debug.Print AL(i) End If Next If AL(i) <> AL(i - 1) Then 'Prints last value if unique by comparing to one before it Debug.Print AL(i) End If Debug.Print GetTickCount - Start End Sub 并循环遍历数组Dim AL(10 ^ 6) As Integer,就可以将ArrayList方法从13秒缩减到0.5秒。

这是有道理的,因为数组的内存分配允许它们被非常快速地处理。这也是为什么有些人喜欢创建他们自己的排序和唯一性算法,而不是采用效率较低但易于使用的方法,采用最初建议的Dictionary或ArrayList。字典和ArrayLists仍然是强大的工具,如上所述,他们仍然可以在几分之一秒内从100万长度中提取独特的值,但值得注意的是,当涉及到原始效率时,一个简单的数组很快就会变坏循环。

以下代码将在约0.3秒内从100万个长度数组中提取唯一值。它与OP没有太大的不同,但效率更高。这是因为循环收集的速度非常慢,不是因为基本策略的效率低下。此外,请注意,随着唯一值的数量增加,效率将降低(此测试仅使用1-10的10个唯一值)。

A = AL.ToArray