Как создать минимальный связанный список Excel-VBA без использования пользовательских классов в VBA - PullRequest
0 голосов
/ 10 сентября 2018

Я пытаюсь создать связанный список в VBA, который избегает:

  1. использование пользовательских классов.
  2. любые ком-объекты, такие как словарь

Ниже я реализовал (VBA, Excel 2016) такой список, используя только операторы VBA, используя коллекции в качестве контейнера для указателя и значения.

Эта реализация хорошо работает по сравнению с добавлением контейнеров в коллекцию (см. Функцию testcollection):

  1. функция LLadd способна добавить 5M элементов менее чем за 15 с по сравнению с 5 с для добавления 5M контейнеров в коллекцию
  2. Итог быстр <3s / 5M предметов </li>
  3. функция LLdelete позволяет избежать ошибки 28 «out of stackspace error», но занимает некоторое время.

Однако проблема заключается в том, что использование памяти довольно велико (5 миллионов элементов ~ 1 ГБ) по сравнению с 250 МБ, если вы используете коллекцию только значений (обратите внимание, что это не то, что здесь делает функция testCollection ... который также использует 1Gb).

Я просмотрел связанные списки, но мне не удалось найти минимальную реализацию, в которой не используются классы.

Есть ли способ повысить эффективность использования памяти в VBA, не прибегая к классам и объектам сценариев?

спасибо заранее!

Option Explicit

' L is an array with 3 elements that provide access to the linkled list'
' it thus represents the list, but is actually a tuple with
'   L(0) the head or first element of the list'
'   L(1) then last element to be replaced with the next element added'
'   L(2) the current element (e.g when iterating)'

' each element C is a collection object with 2 elements'
'collections are able to be referenced (arrays are always copied)
'   C(1): the link to the next element'
'   C(2): the value'

Property Let LLadd(Lst, value)
    'force Lst to exist'
try: On Error GoTo catch
        If Lst(0) Is Nothing Then
catch:    Lst = Array(Nothing, Nothing, Nothing)
        End If
    On Error GoTo 0

    Dim c As New Collection
    If Lst(0) Is Nothing Then 'add head twice'
        c.Add value
        Set Lst(0) = c
        Set Lst(1) = Lst(0)
    Else
        c.Add value
        Lst(1).Add c
        Set Lst(1) = Lst(1)(2)
    End If
End Property


'itterate through the items in de list, '
'maintain the index, and return value'
Function Iterating(L, Optional index, Optional value)
    index = index + 1
    If L(2) Is Nothing Then 'initialise iteration'
        Set L(2) = L(0)
        Iterating = True
        index = 1
        If Not IsMissing(value) Then value = L(2)(1)

    ElseIf L(2) Is L(1) Then 'exit loop'
        Iterating = False
        Set L(2) = Nothing
        If Not IsMissing(value) Then value = Empty

    Else
        Set L(2) = L(2)(2)
        If Not IsMissing(value) Then value = L(1)(1)
        Iterating = True
    End If
End Function

'This function cleans up after the list, error 28 if you dont...'
Sub LLdelete(Lst)
    Dim prev1, c
    Set c = Lst(0)
    While True
        Set prev1 = c
        Set c = c(2)
        prev1.Remove 2
        If c.Count = 1 Then
            Set Lst = Nothing
            Exit Sub
        End If
    Wend
End Sub

Sub testLL()
    Dim L, i
    For i = 1 To 5000000
        LLadd(L) = i + 30
    Next
    i = 0

    Dim s, value
    While Iterating(L, i, value)
        s = s + value
    Wend
    Debug.Print i, s

    LLdelete L
End Sub


'add containers with links to a collection for comparrison'
Sub testcollection()
    Dim L As New Collection, i, c As New Collection, d As Collection
    For i = 1 To 5000000
        Set c = New Collection
        c.Add i + 33
        L.Add c
        If Not d Is Nothing Then d.Add c
        Set d = c
    Next
    i = 0

    Dim s, value
    For Each c In L
        i = i + 1
        s = s + c(1)
    Next
    Debug.Print i, s

    Set L = Nothing
End Sub

Примечание 1 : индекс в итерирующей функции на самом деле не требуется, он только для будущего использования

Примечание 2 : функция TestCollection предназначена для сравнения с коллекцией (это не совсем сопоставимо ...)

Примечание 3 : конечная цель состоит в том, чтобы предоставить больший контроль над каждым циклом (например, обратный foreach, для каждого шага 2 и т. Д., Для каждого с двумя списками одновременно (например, Zip (list1) , List2) в питоне)

...