Работа с массивами в VBA - PullRequest
       7

Работа с массивами в VBA

3 голосов
/ 24 февраля 2011

У меня возникла небольшая проблема с работой с массивами в VBA, где то же самое было бы тривиально на (почти) любом другом языке:

Public Function getArray() As MyType()
    'do a lot of work which returns an array of an unknown length'
    'this is O(N^2) or something equally intensive so I only want to call this once'
End Function

Public Sub doSomething()
    Dim myArray() As MyType
    Set myArray = getArray() 'FAILS with "Cannot assign to array error"'
End Sub

Я думаю, возможно, мне нужноОпределите длину массива заранее или ReDim динамический массив.Но я не знаю длины возвращаемого массива заранее, и я бы хотел избежать вызова функции дважды:

Public Sub doSomething()
    Dim myArray(0 To UBound(getArray()) As MyType  'not entirely sure if this would work, but it involves calling getArray twice which I'd like to avoid
    Set myArray = getArray()
End Sub

В C # или Java эквивалент будет:

public MyType[] getArray(){
    //do some work and return an array of an unknown length
}

public void doSomething(){
    MyType[] myArray;
    myArray = getArray();  //one line and I don't need to define the length of array beforehand
}

Ответы [ 4 ]

2 голосов
/ 24 февраля 2011

При назначении массивов пользовательских объектов в vba вам необходимо передать их как варианты Я включил полный рабочий образец.

Модуль класса с именем MyType:

Public Once As Integer
Public Twice As Integer
Public Thrice As Integer

Код в стандартном модуле:

Public Function getArray() As MyType()
Dim i As Integer, arr() As MyType
    'do a lot of work which returns an array of an unknown length'
    'this is O(N^2) or something equally intensive so I only want to call this once'
    For i = 0 To Int(Rnd() * 6) + 1
        ReDim Preserve arr(i)
        Set arr(i) = New MyType
        arr(i).Once = i
        arr(i).Twice = i * 2
        arr(i).Thrice = i * 3
    Next i
    getArray = arr
    MsgBox "Long process complete"
End Function

Public Sub doSomething()
Static myArray() As MyType
Dim i As Integer
    If UBound(myArray) = -1 Then
        myArray = getArray()
    End If
    For i = LBound(myArray) To UBound(myArray)
        Debug.Print myArray(i).Once & vbTab & _
                    myArray(i).Twice & vbTab & _
                    myArray(i).Thrice
    Next i
End Sub

Public Sub Test()
Dim i As Integer
    For i = 1 To 3
        Debug.Print "Run Number " & i & vbCrLf & String(10, "-")
        doSomething
        Debug.Print
    Next i
End Sub

При первом запуске doSomething будет создан массив произвольной длины, и вы увидите окно с сообщением «Длинный процесс завершен». Последующие вызовы doSomething будут повторно использовать массив, созданный в первый раз.

Если вы скопируете этот код и просто запустите подпрограмму Test, она вызовет doSomething три раза. Вы увидите окно сообщения один раз и три раза вывод doSomething в ближайшем окне.

2 голосов
/ 24 февраля 2011

Ну, вы можете передать массив как ссылку на функцию следующим образом:

Public Sub MyFunc(ByRef arr() As MyType)
  ...
End Sub


Dim myArr() as MyType
MyFunc myArr

Внутри функции вы можете ReDim ваш массив, как хотите.

1 голос
/ 24 февраля 2011

Действительно возможно вернуть массив из функции в VBA. Согласно MSDN :

[Y] Вы также можете вызвать процедуру, которая возвращает массив, и назначить его другому массиву. [. , , ] Обратите внимание, что для возврата массива из процедуры вы просто назначаете массив имени процедуры.

Так что вам просто нужно изменить существующий код, удалив Set из оператора присваивания:

Public Function getArray() As MyType()
    'do a lot of work which returns an array of an unknown length'
    'this is O(N^2) or something equally intensive so I only want to call this once'
End Function

Public Sub doSomething()
    Dim myArray() As MyType
    myArray = getArray
End Sub
1 голос
/ 24 февраля 2011

Я думаю, вам просто нужно избавиться от set в наборе myArray = getArray()


Это ведет себя правильно:

Option Explicit

Public Function getArray() As Integer()
    Dim test(1 To 5) As Integer
    test(1) = 2
    test(2) = 4
    getArray = test
End Function

Public Sub doSomething()
    Dim myArray() As Integer
    myArray = getArray()
    Debug.Print (myArray(2))
End Sub
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...