VBA (Excel) Инициализировать весь массив без циклов

32

Я новичок в VBA, так что это может быть простой вопрос, но здесь идет.

Я хотел бы инициализировать целый массив myArray, скажем, целых чисел, в VBA. Я знаю, что могу сделать это с помощью простой инициализации, например:

Dim myArray
myArray = Array(1, 2, 4, 8)

Но если массив большой, это громоздко, и я хотел бы инициализировать все элементы для одного и того же значения. В идеале это было бы примерно так:

myArray(:) = 0

Я пробовал это, но компилятор жаловался. Затем я попробовал myArray() = 0, и он тоже пожаловался на это.

Может ли кто-нибудь объяснить, как это сделать, без цикла? Я хотел бы сделать это в одном заявлении, если это возможно.

Разъяснение

Я хочу инициализировать каждый отдельный элемент массива до некоторого начального значения. Поэтому, если у меня есть массив Dim myArray(300) As Integer из 300 целых чисел, например, все 300 элементов будут иметь одинаковое начальное значение (например, число 13).

Подробнее Уточнение

Я нашел этот ответ, в котором говорится, что вы можете сделать это с такой переменной:

Dim x As Double: x = 0

Возможно, есть способ немного обновить синтаксис, чтобы применить его к массивам?

  • 1
    : является символом продолжения, если вы хотите, чтобы он был в одной строке для удобства чтения. Попробуйте это Dim myArray : myArray = Array(1, 2, 4, 8)
  • 1
    Связанная переменная microsoft-visual-basic-how-to-initialize-an-array-variable
Теги:
excel-vba
excel
arrays
initialization

7 ответов

24
Лучший ответ

Это легко, по крайней мере, если вам нужен 1-основанный, 1D или 2D вариантный массив:

Sub StuffVArr()
    Dim v() As Variant
    Dim q() As Variant
    v = Evaluate("=IF(ISERROR(A1:K1), 13, 13)")
    q = Evaluate("=IF(ISERROR(A1:G48), 13, 13)")
End Sub

Байт-массивы также не так уж плохи:

Private Declare Sub FillMemory Lib "kernel32" Alias "RtlFillMemory" _
        (dest As Any, ByVal size As Long, ByVal fill As Byte)

Sub StuffBArr()
    Dim i(0 To 39) As Byte
    Dim j(1 To 2, 5 To 29, 2 To 6) As Byte
    FillMemory i(0), 40, 13
    FillMemory j(1, 5, 2), 2 * 25 * 5, 13
End Sub

Вы можете использовать тот же метод для заполнения массивов других числовых типов данных, но вы ограничены только значениями, которые могут быть представлены одним повторяющимся байтом:

Sub StuffNArrs()
    Dim i(0 To 4) As Long
    Dim j(0 To 4) As Integer
    Dim u(0 To 4) As Currency
    Dim f(0 To 4) As Single
    Dim g(0 To 4) As Double

    FillMemory i(0), 5 * LenB(i(0)), &HFF 'gives -1
    FillMemory i(0), 5 * LenB(i(0)), &H80 'gives -2139062144
    FillMemory i(0), 5 * LenB(i(0)), &H7F 'gives 2139062143

    FillMemory j(0), 5 * LenB(j(0)), &HFF 'gives -1

    FillMemory u(0), 5 * LenB(u(0)), &HFF 'gives -0.0001

    FillMemory f(0), 5 * LenB(f(0)), &HFF 'gives -1.#QNAN
    FillMemory f(0), 5 * LenB(f(0)), &H80 'gives -1.18e-38
    FillMemory f(0), 5 * LenB(f(0)), &H7F 'gives 3.40e+38

    FillMemory g(0), 5 * LenB(g(0)), &HFF 'gives -1.#QNAN
End Sub

Если вы хотите избежать цикла в других ситуациях, он становится еще более волосатым. На самом деле это не стоит, если у вашего массива 50K записей или больше. Просто установите каждое значение в цикле, и вы будете достаточно быстры, как я говорил в более раннем ответе.

  • 1
    Способ Evaluate может быть сокращен до v = [Column(A:KN)*0+13] или даже до v = [A1:KN1+13] если вы используете пустой диапазон
10

Вы можете инициализировать массив, указав размеры. Например

Dim myArray(10) As Integer
Dim myArray(1 to 10) As Integer

Если вы работаете с массивами, и если это ваш первый раз, я бы рекомендовал посетить Chip Pearson WEBITE.

Что это инициализирует? Например, что, если я хочу инициализировать весь массив до 13?

Если вы хотите инициализировать массив из 13 элементов, вы можете сделать это двумя способами.

Dim myArray(12) As Integer
Dim myArray(1 to 13) As Integer

В первой нижней границе массива начнется с 0, чтобы вы могли хранить 13 элементов в массиве. Например

myArray(0) = 1
myArray(1) = 2
'
'
'
myArray(12) = 13

Во втором примере вы указали нижние границы как 1, поэтому ваш массив начинается с 1 и может снова хранить 13 значений

myArray(1) = 1
myArray(2) = 2
'
'
'
myArray(13) = 13

Если вы инициализируете массив с использованием любого из вышеперечисленных методов, значение каждого элемента в массиве равно 0. Чтобы проверить, что попробовать этот код.

Sub Sample()
    Dim myArray(12) As Integer
    Dim i As Integer

    For i = LBound(myArray) To UBound(myArray)
        Debug.Print myArray(i)
    Next i
End Sub

или

Sub Sample()
    Dim myArray(1 to 13) As Integer
    Dim i As Integer

    For i = LBound(myArray) To UBound(myArray)
        Debug.Print myArray(i)
    Next i
End Sub

ПОСЛЕДНИЕ ОТ КОММЕНТАРИЙ

Итак, в этом примере каждое значение будет равно 13. Поэтому, если бы у меня был массив Dim myArray (300) As Integer, все 300 элементов имели бы значение 13

Как я уже упоминал, AFAIK, нет прямого способа добиться того, чего вы хотите. Сказав, что это один из способов, который использует функцию рабочего листа Rept для создания повторяющейся строки из 13. Как только мы получим эту строку, мы можем использовать SPLIT, используя "," в качестве разделителя. Но обратите внимание, что это создает вариантный массив, но может использоваться в вычислениях.

Обратите также внимание, что в следующих примерах myArray будет фактически содержать 301 значение, из которых последний пуст - вам придется учитывать это, дополнительно инициализируя это значение или удаляя последние "," из sNum перед операцией SPLIT.

Sub Sample()
    Dim sNum As String
    Dim i As Integer
    Dim myArray

    '~~> Create a string with 13 three hundred times separated by comma
    '~~> 13,13,13,13...13,13 (300 times)
    sNum = WorksheetFunction.Rept("13,", 300)
    sNum = Left(sNum, Len(sNum) - 1)

    myArray = Split(sNum, ",")

    For i = LBound(myArray) To UBound(myArray)
        Debug.Print myArray(i)
    Next i
End Sub

Использование массива вариантов в вычислениях

Sub Sample()
    Dim sNum As String
    Dim i As Integer
    Dim myArray

    '~~> Create a string with 13 three hundred times separated by comma
    sNum = WorksheetFunction.Rept("13,", 300)
    sNum = Left(sNum, Len(sNum) - 1)

    myArray = Split(sNum, ",")

    For i = LBound(myArray) To UBound(myArray)
        Debug.Print Val(myArray(i)) + Val(myArray(i))
    Next i
End Sub
  • 0
    К чему это инициализируется? Например, что если я хочу инициализировать весь массив до 13?
  • 0
    Обновление моего ответа на основе вашего комментария выше.
Показать ещё 5 комментариев
4

Я хочу инициализировать каждый отдельный элемент массива до некоторого начального значения. Поэтому, если у меня есть массив Dim myArray (300). Так как целое число из 300 целых чисел, например, все 300 элементов будут иметь одинаковое начальное значение (например, число 13).

Может ли кто-нибудь объяснить, как это сделать, без цикла? Я бы хотел сделать это в одном заявлении, если это возможно.

Что я выиграю?

Sub SuperTest()
   Dim myArray
   myArray = Application.Transpose([index(Row(1:300),)-index(Row(1:300),)+13])
End Sub
  • 0
    хороший ответ. я думаю, что это даже немного лучше, хотя myArray = [A1:KN1+13]
1

Эта функция работает с переменными для размера и начального значения, она объединяет ответы tbur и Filipe.

Function ArrayIniValue(iSize As Integer, iValue As Integer)
Dim sIndex As String
sIndex = "INDEX(Row(1:" & iSize & "),)"
ArrayIniValue = Evaluate("=Transpose(" & sIndex & "-" & sIndex & "+" & iValue & ")")
End Function

Вызывается следующим образом:

myArray = ArrayIniValue(350, 13)
0

Один метод, который может использоваться для назначения значений целым элементам массива, заключается в том, чтобы поместить данные на неиспользованный рабочий лист и затем прочитать значения из листа в массив. Например, я хочу присвоить значения 123 целым элементам массива 5x5. Вот однострочный код для реализации такой задачи:

ReDim MyArray(1 To 5, 1 To 5): Range("A1:E5") = 123: MyArray = Range("A1:E5")

Хотя он немного медленный, но он отлично работает. Вы также можете удалить объявление массива.

Range("A1:E5") = 123: MyArray = Range("A1:E5")

Фактически вы можете легко изменить значение некоторых элементов. Например, предположим, что вы хотите изменить значение элементов MyArray (1,1), MyArray (1,5), MyArray (3,3), MyArray (5,1) и MyArray (5,5) до 789, тогда код будет таким:

Range("A1:E5") = 123: Range("A1,E1,C3,A5,E5") = 789: MyArray = Range("A1:E5")
  • 0
    Это добавило бы к вычислительной стоимости. Для небольших массивов это бы сработало.
0

Необычный способ ответа @rdhs на функцию:

Function arrayZero(size As Integer)
  arrayZero = Evaluate("=IF(ISERROR(Transpose(A1:A" & size & ")), 0, 0)")
End Function

И используйте вот так:

myArray = arrayZero(15)
0

Для VBA вам нужно инициализировать две строки.

Sub TestArray()

Dim myArray
myArray = Array(1, 2, 4, 8)

End Sub
  • 0
    Спасибо за комментарий, но это делает то, что я упомянул в вопросе - я ищу, чтобы инициализировать entire массив одним значением в одном кадре.
  • 1
    @ user1205577 Dim myArray = New Integer() {1, 2, 4, 8} является допустимым синтаксисом для vb.net, но не для vba. Для VBA вы должны сделать это так, как я предложил, если вы не хотите зацикливаться.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню