Vba excel расширение массива

Массивы в VBA Excel: одномерные, многомерные и динамические. Объявление и использование массивов. Операторы Public, Dim и ReDim. Функции Array, LBound, UBound.

Массивы – это множества однотипных элементов, имеющих одно имя и отличающиеся друг от друга индексами. Они могут быть одномерными (линейными), многомерными и динамическими. Массивы в VBA Excel, как и другие переменные, объявляются с помощью операторов Dim и Public. Для изменения размерности динамических массивов используется оператор ReDim. Массивы с заранее объявленной размерностью называют статическими.

Одномерные массивы

Объявление одномерных (линейных) статических массивов в VBA Excel:

Public Massiv1(9) As Integer

Dim Massiv2(1 To 9) As String

В первом случае публичный массив содержит 10 элементов от 0 до 9 (нижний индекс по умолчанию — 0, верхний индекс — 9), а во втором случае локальный массив содержит 9 элементов от 1 до 9.

По умолчанию VBA Excel считает в массивах нижним индексом нуль, но, при желании, можно сделать нижним индексом по умолчанию единицу, добавив в самом начале модуля объявление «Option Base 1».

Многомерные массивы

Объявление многомерных статических массивов в VBA Excel аналогично объявлению одномерных массивов, но с добавлением размерностей дополнительных измерений через запятую:

‘Массив двухмерный

Public Massiv1(3, 6) As Integer

‘Массив трехмерный

Dim Massiv2(1 To 6, 1 To 8, 1 To 5) As String

‘Массив четырехмерный

Dim Massiv3(9, 9, 9, 9) As Date

Третий массив состоит из 10000 элементов — 10×10×10×10.

Динамические массивы

Динамические массивы в VBA Excel, в отличие от статических, объявляются без указания размерности:

Public Massiv1() As Integer

Dim Massiv2() As String

Такие массивы используются, когда заранее неизвестна размерность, которая определяется в процессе выполнения программы. Когда нужная размерность массива становится известна, она в VBA Excel переопределяется с помощью оператора ReDim:

Public Massiv1() As Integer

Dim Massiv2() As String

ReDim Massiv1(1 To 20)

ReDim Massiv2(3, 5, 4)

При переопределении размерности массива вместо верхнего индекса можно использовать переменную:

Dim Massiv1() as Variant, x As Integer

x = 20

ReDim Massiv1(1 To x)

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

С помощью оператора ReDim невозможно изменить обычный массив, объявленный с заранее заданной размерностью. Попытка переопределить размерность такого массива вызовет ошибку компиляции с сообщением: Array already dimensioned (Массив уже измерен).

При переопределении размерности динамических массивов в VBA Excel теряются значения их элементов. Чтобы сохранить значения, используйте оператор Preserve:

Dim Massiv1() As String

операторы

ReDim Massiv1(5, 2, 3)

операторы

ReDim Preserve Massiv1(5, 2, 7)

Обратите внимание!
Переопределить с оператором Preserve можно только последнюю размерность динамического массива. Это недоработка разработчиков, которая сохранилась и в VBA Excel 2016. Без оператора Preserve можно переопределить все размерности.

Максимальный размер

Размер массива – это произведение длин всех его измерений. Он представляет собой общее количество элементов, содержащихся в данный момент в массиве.

По информации с сайта разработчиков, максимальный размер массивов зависит от операционной системы и доступного объема памяти. Использование массивов, размер которых превышает объем доступной оперативной памяти компьютера, приводит к снижению скорости, поскольку системе необходимо выполнять запись данных и чтение с диска.

Использование массивов

Приведу два примера, где не обойтись без массивов.

1. Как известно, функция Split возвращает одномерный массив подстрок, извлеченных из первоначальной строки с разделителями. Эти данные присваиваются заранее объявленному строковому (As String) одномерному динамическому массиву. Размерность устанавливается автоматически в зависимости от количества подстрок.

2. Данные в массивах обрабатываются значительно быстрее, чем в ячейках рабочего листа. Построчную обработку информации в таблице Excel можно наблюдать визуально по мерцаниям экрана, если его обновление (Application.ScreenUpdating) не отключено. Чтобы ускорить работу кода, можно значения из диапазона ячеек предварительно загрузить в динамический массив с помощью оператора присваивания (=). Размерность массива установится автоматически. После обработки данных в массиве кодом VBA полученные результаты выгружаются обратно на рабочий лист Excel. Обратите внимание, что загрузить значения в диапазон ячеек рабочего листа через оператор присваивания (=) можно только из двумерного массива.

Функции Array, LBound, UBound

Функция Array

Функция Array возвращает массив элементов типа Variant из первоначального списка элементов, перечисленных через запятую. Нумерация элементов в массиве начинается с нуля. Обратиться к элементу массива можно, указав в скобках его номер (индекс).

Sub Test1()

Dim a() As Variant

a = Array(«text», 25, «solo», 35.62, «stop»)

MsgBox a(0) & vbNewLine & a(1) & vbNewLine _

& a(2) & vbNewLine & a(3) & vbNewLine & a(4)

End Sub

Скопируйте код в модуль VBA Excel и запустите его на выполнение. Информационное сообщение MsgBox покажет значения массива, извлеченные по индексу.

Функция LBound

Функция LBound возвращает значение типа Long, равное наименьшему (нижнему) доступному индексу в указанном измерении массива.
Синтаксис:
LBound (arrayname[, dimension])

  • arrayname — это имя переменной массива, является обязательным аргументом;
  • dimension — это номер измерения массива, необязательный аргумент, по умолчанию принимает значение 1.

Наименьший индекс по-умолчанию может быть равен 0 или 1 в зависимости от настроек оператора Option Base. Нижняя граница архива, полученного с помощью функции Array, всегда равна 0.

При объявлении переменных массивов или переопределении их размерности наименьшие индексы могут быть любыми целыми числами, в том числе отрицательными.

Функция UBound

Функция UBound возвращает значение типа Long, равное наибольшему (верхнему) доступному индексу в указанном измерении массива.
Синтаксис:
UBound( arrayname[, dimension])

  • arrayname — это имя переменной массива, является обязательным аргументом;
  • dimension — это номер измерения массива, необязательный аргумент, по умолчанию принимает значение 1.

Функция UBound используется вместе с функцией LBound для определения размера массива.

Sub Test2()

Dim a(2 To 53) As String

MsgBox «Наименьший индекс = « & LBound(a) & _

vbNewLine & «Наибольший индекс = « & UBound(a)

End Sub

Скопируйте код в модуль VBA Excel и запустите его на выполнение. Информационное сообщение MsgBox покажет значения наименьшего и наибольшего индекса переменной массива a.

Обход массива циклом

Обход одномерного массива циклом For… Next, в котором для определения границ массива используются функции UBound и LBound:

Sub Test3()

Dim a() As Variant, i As Long

a = Array(«text», 25, «solo», 35.62, «stop»)

    For i = LBound(a) To UBound(a)

        Debug.Print «a(« & i & «) = « & a(i)

    Next

End Sub

Результат работы цикла вы увидите в окне Immediate.

Очистка (обнуление) массивов

Первый способ

Очистить любой массив, статический или динамический, без использования цикла можно с помощью оператора Erase. Термин «обнуление» можно применить только к массиву числового типа.

Dim Massiv1(4, 3) As String,  Massiv2() As Variant

операторы

‘переопределяем динамический массив

ReDim Massiv2(2, 5, 3)

операторы

‘очищаем массивы

Erase Massiv1

Erase Massiv2

Обратите внимание, что оба массива при таком способе очистки будут возвращены в исходное состояние, которое они имели сразу после объявления:

  • статический Massiv1 сохранит размерность (4, 3);
  • динамический Massiv2 не сохранит размерность ().

Второй способ

Динамический массив можно очистить (обнулить) без использования цикла с помощью оператора ReDim. Просто переопределите его с той же размерностью.

Dim Massiv() As Double

операторы

‘переопределяем массив

ReDim Massiv(5, 6, 8)

операторы

‘очищаем массив

ReDim Massiv(5, 6, 8)


 

Kazanildarik

Пользователь

Сообщений: 38
Регистрация: 06.04.2017

#1

29.04.2022 10:31:21

Всем привет!
Подскажите пожалуйства, как расширять динамический массив по мере появления новых данных, при их сборе циклом?
Второй день ковыряюсь, ошибку все найти не могу)))  Статей много прочёл, но с места сдвинуться не могу))

Код
Sub test()
LastRow = 2
Dim arr() As Variant
ReDim arr(1 To 1, 1 To 4)
Dim i%, k%

For i = 1 To LastRow
        k = k + 1
        ReDim Preserve arr(1 To UBound(arr, 1) + 1, 1 To 4) 'вылетает ошибка subscrpt out of range
        arr(k, 1) = "Привет"
        arr(k, 2) = "Пусто"
        arr(k, 3) = "Пусто"
        arr(k, 4) = "и снова здравствуйте"
Next i

Range("A1:D2") = arr
End Sub

Изменено: Юрий М29.04.2022 11:48:35

 

Jack Famous

Пользователь

Сообщений: 10848
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#2

29.04.2022 10:37:14

Код
Sub test()

Dim arr(), i&
Const LastRow& = 2

ReDim arr(1 To LastRow, 1 To 4)

For i = 1 To LastRow
        arr(k, 1) = "Привет"
        arr(k, 2) = "Пусто"
        arr(k, 3) = "Пусто"
        arr(k, 4) = "и снова здравствуйте"
Next i
 
Range("A1").Resize(UBound(arr,1), UBound(arr,2) ).Value = arr
End Sub

А по вашему вопросу:

ReDim Preserve может менять только ПОСЛЕДНЮЮ размерность массива (столбцы — в данном случае). Вот

тут

подробнее про массивы.

Изменено: Jack Famous29.04.2022 10:40:07

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

Дмитрий(The_Prist) Щербаков

Пользователь

Сообщений: 14182
Регистрация: 15.09.2012

Профессиональная разработка приложений для MS Office

#3

29.04.2022 10:38:14

Preserve работает только с последней размерностью. Т.е. только так:

Код
ReDim Preserve arr(1 To 4, 1 To UBound(arr, 1) + 1)

а потом транспонировать

Код
Range("A1:D2") = Application.Transpose(arr)

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

 

Большое спасибо)))
Проще перебрать на условие отдельно, потом задать массив и заполнить его тогда

 

МатросНаЗебре

Пользователь

Сообщений: 5516
Регистрация: 05.02.2014

#5

29.04.2022 10:44:34

Код
Sub test()
Const LastRow = 2
Dim brr As Variant
ReDim brr(1 To 4)
Dim arr() As Variant
ReDim arr(1 To 1)
Dim i%, k%
For i = 1 To LastRow
    brr(1) = "Привет"
    brr(2) = i
    brr(3) = "Пусто"
    brr(4) = "и снова здравствуйте"
    arr(UBound(arr)) = brr
    ReDim Preserve arr(1 To UBound(arr) + 1)
Next i
Dim crr As Variant
ReDim crr(1 To UBound(arr) - 1, 1 To UBound(brr))
For i = 1 To UBound(crr, 1)
    For k = 1 To UBound(crr, 2)
        crr(i, k) = arr(i)(k)
    Next
Next
Range("A1:D2") = crr
End Sub
 

Ігор Гончаренко

Пользователь

Сообщений: 13746
Регистрация: 01.01.1970

#6

29.04.2022 10:56:37

Цитата
Kazanildarik написал:
Проще перебрать на условие отдельно, потом задать массив

если знаете как проще, к чему вопросы? делайте как проще и задача решена

Программисты — это люди, решающие проблемы, о существовании которых Вы не подозревали, методами, которых Вы не понимаете!

 

Не понимал что можно менять только последнюю размерность.
Обойти это ограничесние можно вариантами что предложили

 

Юрий М

Модератор

Сообщений: 60575
Регистрация: 14.09.2012

Контакты см. в профиле

Кто предложит адекватное название темы?

 

Не претендуя на адекватность )
Изменение размерности двумерного массива

 

Jack Famous

Пользователь

Сообщений: 10848
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#10

29.04.2022 12:10:57

Цитата
Kazanildarik: Проще перебрать на условие отдельно, потом задать массив и заполнить его тогда

быстрее задать массив с запасом в разумных пределах, если это можно, а как делать в вашем случае, я показал — никакого изменения размерности не нужно

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

Содержание:

  • Зачем нужны массивы

  • Что такое массив

  • Типы массивов

  • Объявление массивов

  •     Объявление фиксированных массивов
  •     Объявление динамических массивов
  • Изменение элементов массива

  • Чтение элементов массива

  • Определение границ массива

  • Перебор элементов массива

  • Передача массивов в подпрограммы

  • Массив с элементами типа массив

  • Функция Array

  • Функция Split

  • Нюансы работы с динамическими массивами

  •     Неинициализированный массив
  •     Расширение массива
  •     Удаление массива
  • Получение массива на основе диапазона Excel

  • Дополнительные источники

Зачем нужны массивы

Массивы очень упрощают процесс программирования. Без них практически невозможно написать универсальную программу. Например, представьте себе, что вы манипулируете информацией о квартирах жилого дома. Вы объявляете переменные K1 — для первой квартиры, K2 — для второй и так далее. K1=54 будет означать, что площадь первой квартиры 54 кв.м., К2=72 и т.д. Теперь представим, что нам надо подсчитать общую площадь всех квартир в доме. Очевидно, что это что-то типа Total_S = K1+K2+…+Kn. В одном доме у нас 36 квартир, а в другом 144. Представляете бредовость процесса подобного программирования? Если в первом случае я должен буду использовать 36 отдельных переменных для вычисления общей площади, то для второго дома уже 144. Очень быстро вы придёте к мысли, что вам нужна переменная, состоящая из нумерованных ячеек. Тогда обретают смысл все те операторы циклов, входящие в состав любого языка программирования. Но об этом чуть позже…

▲ вверх

Что такое массив

Массив — переменная, состоящая из некоторого количества однотипных элементов. У массива, как и у любой другой переменной, есть имя. А доступ к конкретному элементу массива осуществляется через указание в скобках после имени его индекса. Например, A(5) означает, что я обращаюсь к элементу с индексом 5 массива, имеющего имя A.

▲ вверх

Типы массивов

Массивы в VBA и во многих других языках программирования делятся на 2 класса:

  • Фиксированные массивы. Такие массивы состоят из заранее известного количества элементов. Это количество определяется во время объявления массива и уже не может быть изменено в процессе его жизненного цикла. Вы, конечно же, сможете использовать меньшее количество элементов, но не существует способа увеличить количество элементов сверх объявленного.

  • Динамические массивы. Эти массивы можно «переобъявлять» в процессе жизненного цикла. То есть мы можем управлять количеством элементов динамических масивов в зависимости от наших потребностей. Это очень удобно, так как в подавляющем большинстве случаев программист не может заранее знать, с каким объёмом данных он столкнётся. Если вы собираетесь писать более-менее универсальные программы, то этот тип массивов определенно стоит изучить.

▲ вверх

Объявление массивов

Объявление фиксированных массивов

Рекомендация: при объявлении массивов VBA я советую вам давать всем именам префикс «arr«. Я сторонник венгерской нотации.

Как мы видим, тут объявлено 2 одномерных массива arrTemp и arrTest. Одномерные массивы в программировании также часто называют векторами. Типом элементов первого массива является Long, второго массива — String. В этом типе синтаксиса в скобках указан максимальный индекс (верхняя граница ) элемента массива. А что насчёт минимального индекса (нижней границы) массива? По-умолчанию минимальным индексом является ноль. В данном случае стандартное поведение интерпретатора языка VBA можно изменить при помощи оператора option base {0|1}. Option base 1 заставляет VBA считать нижней границей массива — единицу, а не ноль.

Таким образом, по-умолчанию массив arrTemp имеет 11 элементов — от 0 до 10. Но, если в начало модуля, в котором этот массив объявляется, вставить оператор Option Base 1, то массив arrTemp будет иметь 10 элементов — от 1 до 10.

Помимо вышеуказанного вы вправе использовать следующий синтаксис, который НЕ зависит от option base {0|1}:

таким образом вы в явном виде указываете и нижнюю, и верхнюю границы. Как видите, нижняя граница совершенно не обязательно должна начинаться с 0 или 1. Более того, индексы границ могут принимать и отрицательные значения, главное чтобы нижняя была меньше верхней.

Помимо одномерных массивов, можно объявлять и массивы с размерностью больше единицы.

arrMulti — двумерный массив, а arrData3 — трёхмерный. Первый содержит 11*31=341 элемент, второй — 2*3*10=60 элементов. Теоретически допускается объявлять до 60 размерностей массива.

Какие типы данных могут стать элементами массива? Тут всё, как в шутке про фамилию еврея, — абсолютно любой тип данных годится на роль элемента массива, включая объектные типы, User Data Type, другие массивы (через тип Variant). Если вы не указываете при объявлении тип данных массива, то предполагается, что этим типом является тип Variant.

▲ вверх

Объявление динамических массивов

Динамические массивы объявляться так:

Однако, использовать их после такого объявления пока ещё нельзя. Необходимо выделить память под массив. Особенность работы с динамическим массивом как раз состоит в том, что программист отвечает за его своевременное расширение (усечение) в памяти. Для этого существует специальный оператор, который имеет следующий синтаксис:

    ReDim [Preserve] varname(subscripts) [As Type]

Например:

После этого оператора, вы можете использовать элементы массива arrOpen с 0-го по 5-й. Всё, что мы говорили про оператор option base и нижнюю границу, верно и для динамических массивов. Предположим, что вы сохранили информацию в элементах 0-5 и у вас поспела новая порция информации для элементов 6-11. Чтобы разместить в данном массиве новые элементы и не потерять старые, вы должны сделать следующее:

то есть мы тут увеличиваем верхнюю границу массива и используем ключевое слово Preserve, чтобы во время этой операции не потерять текущее содержимое arrOpen, так как в противном случае (без слова Preserve) массив будет расширен, а память заполнена нулями. Вы также вправе вообще не декларировать массив оператором Dim, а сделать это впервые через ReDim и там же указать лип элементов. Но, если вы в первом ReDim (или Dim) указали определенный тип элементов, то в последующих операторах ReDim этот тип переопределён быть не может — возникнет ошибка на этапе компиляции проекта.

▲ вверх

Изменение элементов массива

Пора бы нам уже научиться пользоваться нашими массивами — то есть записывать информацию в их элементы и считывать её оттуда. Это довольно просто:

Как и с обычными переменными запись информации в элемент массива происходит через оператор присваивания (=), но указанием индекса элемента массива.

▲ вверх

Чтение элементов массива

▲ вверх

Определение границ массива

В подпрограммах часто приходится иметь дело с массивами, которые переданы вам в качестве параметра (как это сделать показано ниже), поэтому в этом случае очень актуален вопрос определения нижней и верхней границ индекса массива. Для этого в языке предусмотрены 2 функции: LBound и UBound. Первая возвращает нижнюю границу индекса, вторая — верхнюю.

    LBound( array [, dimension])

    UBound( array [, dimension])

Для одномерных массивов параметр dimension можно не указывать. Для многомерных массивов его указывать необходимо. Кстати, это означает, что, если вы точно не знаете, с каким массивом имеете дело, но необходимо узнать его первую размерность, то лучше использовать вариант UBound(arrTemp,1), а не UBound(arrTemp), так как последний вариант вызовет ошибку, если массив окажется многомерным.

Если вы ошибётесь с указанием правильного индекса массива, то возникнет ошибка периода исполнения с кодом 9. Эта же ошибка возникнет, если вы в функции LBound / UBound укажете несуществующую размерность массива (например, 3 для двумерного массива).

▲ вверх

Перебор элементов массива

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

Наиболее удобный оператор цикла для перебора элементов массива — это безусловно ForNext.

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

Вы, конечно, можете перебирать массив и в других типах циклов DoLoop, но, право, смысла и удобства в этом не много. По крайней мере я не сталкивался, кажется, с ситуациями, когда для перебора массива цикл For не подошёл.

▲ вверх

Передача массивов в подпрограммы

Массивы удобнее всего передавать в подпрограммы в виде параметра типа Variant.

Обратите внимание, что функции GetResult в качестве параметра передаются массивы. При чём, в первом случае это массив с типом элементов Long, а во втором — String. За счёт того, что внутри функции используются переменные типа Variant, то сначала функция нам возвращает сумму элементов массива arrIntegers, а во втором результат сложения (конкатенации) строк массива arrStrings. Кроме того, параметр parArray не описан как массив (parArray As Variant), но мы внутри функции GetResult ведём себя с ним, как с массивом (For Each Element In parArray)! Это возможно, так как переменные типа Variant умеют определять, что им присваивается и вести себя далее в соответствии с тем, что они содержат. Если переменной parArray присвоили массив (через вызов функции — строки 17 и 18), то она себя будет вести как массив.

▲ вверх

Массив с элементами типа массив

Продемонстрируем, как можно хранить в качестве элементов массива другие массивы.

Результат отладочной печати:

▲ вверх

Функция Array

Данная функция полезна для создания справочных массивов. Она возвращает переменную типа Variant, содержащую одномерный массив с типом элементов Variant.

    Array( arglist )

Вызов функции без параметров приведёт к возврату массива нулевой длинны. При этом будет наблюдаться интересный эффект LBound вернёт вам 0, а UBound вернёт -1, то есть верхняя граница окажется меньше нижней границы.

▲ вверх

Функция Split

Split возвращает одномерный массив, содержащий подстроки, из строкового выражении с учётом указанного разделителя

    Split(expression[, delimiter[, limit[, compare]]])

  • expression — строковое выражение, содержащая подстроки и разделители. Обязательный параметр.

  • delimiter — текстовый разделитель. Необязательный параметр. Если опущен, то предполагается, что разделителем является символ пробела.

  • limit — количество подстрок, которое необходимо вернуть. -1 или отсутствие параметра означает, что вернуть надо все подстроки.

  • compare — константа, указывающая тип сравнения для символов разделителей. 1 — текстовое сравнение (без учёта регистра), 0 — бинарное сравнение (с учётом регистра).

Результат выглядит так:

Если вы в качестве разделителя укажете пустую строку, то на выходе получите массив, состоящий из одного элемента. Кстати, split всегда возвращает массив с нулевой нижней границей вне всякой зависимости от наличия option base 1.

▲ вверх

Нюансы работы с динамическими массивами

Неинициализированный массив

У динамического массива есть такое промежуточное состояние, когда он уже объявлен, но ещё не содержит никаких элементов.

То есть у переменной динамического массива есть такое состояние, когда мы не можем воспользоваться вспомогательными функциями LBound / UBound для определения его (массива) статуса. Это особенно надо учитывать, когда вы пишите подпрограммы, работающие с массивами. Прежде чем работать (перебирать) массив необходимо убедиться, что он проинициализирован, в противном случае программа вылетит с ошибкой 9.

Для этого я предлагаю пользоваться функцией подобной нижеописанной IsNotEmptyArray:

▲ вверх

Расширение массива

Как правило, расширять динамический массив приходится в цикле. Возможны 2 стратегии: расширение на 1 элемент, как только в этом есть необходимость (назовём это эластичным расширением), и расширение авансом, когда вы увеличиваете верхнюю границу скачками, скажем сразу на 100 элементов. Реализовав оба варианта, я для себя сделал вывод, что авансовое расширение получилось и компактнее, и работает быстрее, так как операция расширения, вообще говоря, затратна и, чем реже вызывается, тем лучше.

Результат:

Авансовый метод вышел даже компактнее

▲ вверх

Удаление массива

Существует оператор Erase, который полностью освобождает память из-под динамического массива. Будучи вызванным для статического массива он его обнуляет, а если он строковый, то элементам присваивается пустые строки.

▲ вверх

Самый эффективный по скорости способ получить содержимое диапазона Excel для манипулирования в VBA — это скопировать его в массив с элементами Variant. Делается так:

Даже, если вы передаёте в массив столбец или строку, получаемый массив всегда будет иметь 2 измерения. Измерение 1 отвечает за строки, измерение 2 — за столбцы. То есть ячейка C5 будет в элементе arrTemp(5,3). Нижняя граница таких массивов всегда будет начинаться с единицы.

▲ вверх

Дополнительные источники

В качестве источника дополнительной информации по массивам я могу порекомендовать замечательный, исчерпывающий ресурс Чарльза Пирсона (Charles H. Pearson). Его сайт следует штудировать всем, кто серьёзно осваивает VBA. Конкретно по массивам там огромное количество готовых подпрограмм для работы с ними, исходные коды, снабженные подробнейшими комментариями, продвинутые объяснения для копающих в глубину. Без преувеличения великолепный ресурс!

▲ вверх

Читайте также:

  • Работа с объектом Range

  • Поиск границ текущей области

  • Структуры данных и их эффективность

  • Автоматическое скрытие/показ столбцов и строк

The Excel VBA ReDim statement initializes and resizes a dynamic VBA Array. Be sure to check the difference between Fixed VBA Arrays and Dynamic VBA Arrays.

ReDim [Preserve] varname ( subscripts ) 

Parameters

Preserve
Optional. Keyword to be used if you want to resize your array and keep all items intact.
varname
The name of the array variable.
subscripts
The subscripts of the array defining either it’s upper bounds or lower and upper bounds. See examples below.

Using ReDim with single dimension arrays

Below an example of sizing and resizing a VBA Array:

Dim arr() As Variant 'declaration of variant array
ReDim arr(2) 'Sizing array to upper bound 2. Array size is 3 -> 0 to 2
arr(2) = 10
Debug.Print arr(2) 'Result: 10

ReDim arr(1 to 2) 'Resizing array to size 2 -> 1 to 2. All items will be empty again.
Debug.Print array(2) 'Result: Empty

Using ReDim to resize an array but preserving its contents

Below an example of sizing and resizing a VBA Array, but keeping its contents preserved:

Dim arr() As Variant 'declaration of variant array
ReDim arr(2) 'Sizing array to upper bound 2. Array size is 3 -> 0 to 2
arr(2) = 10
Debug.Print arr(2) 'Result: 10

ReDim Preserve arr(1 to 2) 'Resizing array to size 2 -> 1 to 2. All items will be Preserved as keyword was used.
Debug.Print array(2) 'Result: 10. Hurray!

Using ReDim with multidimensional arrays

Below an example of sizing and resizing a multidimensional array:

Dim arr() As Variant 'declaration of variant array
ReDim arr(2, 2)
arr(1, 1) = 10
    
ReDim Preserve arr(2, 10)
Debug.Print arr(1, 1) 'Result: 10

Return to VBA Code Examples

In this Article

  • Dynamic Array
    • Dynamic Variant Arrays
  • Redim vs. Redim Preserve
    • Using ReDim
    • Using ReDim Preserve

This tutorial will demonstrate how to use dynamic arrays (redim and redim preserve) in VBA.

Dynamic Array

Dynamic Arrays are arrays that can change sizes (as opposed to static arrays, which are static).

To declare a dynamic array, you declare the array, but omit the array size:

Dim strNames() As String

Then, before you can assign values to your array, you must use the ReDim Statement to set the array to your desired size:

ReDim strNames(1 to 3)

Now, anytime you want to change your array size, simply use ReDim (or ReDim Preserve as we’ll learn about below).

Dynamic Variant Arrays

Note: Variant Arrays are a little different. With variant arrays, you don’t need to set the array size with ReDim before assigning values.

Sub TestArray()
'declare the variable
    Dim varNames() As Variant
'populate the array
    varNames() = Array("Fred", "Wilma", "Barney", "Betty")
'return the values
    MsgBox Join(varNames, ",")
End Sub

Redim vs. Redim Preserve

The ReDim statement resizes an array, clearing all existing values.

The ReDim Preserve statement resizes an array, keeping (“preserving”) all existing values.

Using ReDim

In practice, resizing an array with ReDim looks like this:

Sub TestReDim()
'declare the string array
   Dim strNames() As String
'resize the string array to be able to hold 3 values
   ReDim strNames(1 to 3)
'populate the array with 3 names
   strNames(1) = "Mel"
   strNames(2) = "Steve"
   strNames(3) = "Bob"
'show the result in the immediate window
   Debug.Print Join(strNames, vbCrLf)
End Sub

vba redim output 1

Using ReDim Preserve

In this example, we will use ReDim to set the initial dynamic array and then ReDim Preserve to resize the array, keeping the original values:

Sub TestReDim()
'declare the string array
   Dim strNames() As String
'resize the string array to be able to hold 3 values
   ReDim strNames(1 to 3)
'populate the array
   strNames(1) = "Mel"
   strNames(2) = "Steve"
   strNames(3) = "Bob"
'show the result in the immediate window
   Debug.Print Join(strNames, vbCrLf)
'redim but preseve the data
   ReDim Preserve strNames(1 to 4)
   strNames(4) = "Fred"
'show the result in the immediate window
   Debug.Print Join(strNames, vbCrLf)
End Sub

vba redim output 2

If you do not use the PRESERVE statement, you would lose the data that had been in the array previously.

vba redim output 3

In the  immediate window above, the array populated Mel, Steve and Bob.  When it was re-declared, it remove those values and instead returned 3 blank values and then the value ‘Fred’.   This is due to the PRESERVE statement being omitted.

VBA Coding Made Easy

Stop searching for VBA code online. Learn more about AutoMacro — A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!
vba save as

Learn More!

Excel VBA ReDim Statement

The VBA ReDim statement is similar to the Dim statement. But, the difference is that one may use it to store or allocate more storage space or decrease the storage space a variable or an array has. Now, there are two important aspects used with the statement: Preserve. If one uses Preserve with this statement, it creates a new array with different sizes. But, on the other hand, if one does not use Preserve with this statement, it just changes the array size of the current variable.

Arrays are an important part of VBA coding. Using arrays, we can store more than one value in the same variable we defined. Like how we declare the variable using the word “Dim,” we need to declare the array name by using “Dim” as well.

To declare the array name, we need first to identify the kind of array we are going to define. In arrays, we have 5 types:

  1. Static Array
  2. Dynamic Array
  3. One Dimensional Array
  4. Two Dimensional Array
  5. Multi-Dimensional Array

In the static array in excelArray formulas are extremely helpful and powerful formulas that are used in Excel to execute some of the most complex calculations. There are two types of array formulas: one that returns a single result and the other that returns multiple results.read more, we will decide the lower value and upper value of the array well in advance while declaring the variable. For example, look at the below example.

Code:

Sub ReDim_Example1()
  
  Dim MyArray(1 To 5) As String

End Sub

MyArray is the array’s name, which can hold the value from 1 to 5. So, for example, MyArray can hold 5 different results, like the one below.

Code:

Sub ReDim_Example1()
  Dim MyArray(1 To 5) As String

  MyArray(1) = "Hi"
  MyArray(2) = "Good"
  MyArray(3) = "Morning"
  MyArray(4) = "Have a"
  MyArray(5) = "Nice Day"

End Sub
Table of contents
  • Excel VBA ReDim Statement
    • Dynamic Array with ReDim Statement
    • Examples to use VBA Redim Statement
      • Example #1
      • Example #2 – Resize the Array Size While Remembering the Old Values.
    • Things to Remember Here
    • Recommended Articles

Dynamic Array with ReDim Statement

But in the dynamic array, this is not the case. Therefore, we will not decide on the lower and upper values well in advance. Rather, we define the array name and assign data type.

Sub ReDim_Example1()

Dim MyArray() As String

End Sub

To make the array name dynamic, we need to declare it with the word “Dim” first, but don’t decide the array size well in advance. Instead, we name an array with empty values inside the parenthesis (). When the array does not include size, it treats it as a dynamic array.

Dim MyArray() As String

When you mention the array size inside the parenthesis, it becomes a static array. Dim MyArray(1 to 5) As String.

In the dynamic array, we always resize the array size by using the word “ReDim” in the next line of the code.

ReDim MyArray(1 to 6) As String

Any value stored to the array name in the previous steps, i.e., using the “Dim” statement, stands null, and the size we declared using “ReDim” becomes the new size of the array.

Examples to use VBA Redim Statement

You can download this VBA ReDim Excel Template here – VBA ReDim Excel Template

Example #1

Look at the example of using the “ReDim” statement practically. Then, follow the below steps to apply “ReDim.”

Step 1: Create a macro name first.

Step 2: Declare an array name as a string.

Code:

Sub ReDim_Example1()

  Dim MyArray() As String

End Sub

Example 1

Step 3: Now, use “Redim” and assign the array size.

Code:

Sub ReDim_Example1()

  Dim MyArray() As String
  ReDim MyArray(1 To 3)

End Sub

Redim VBA Example 1-1

Step 4: The array name “MyArray” can hold up to 3 values here. Assign the value to these 3 arrays like the below one.

Code:

Sub ReDim_Example1()

  Dim MyArray() As String
  ReDim MyArray(1 To 3)

  MyArray(1) = "Welcome"
  MyArray(2) = "to"
  MyArray(3) = "VBA"

End Sub

Redim VBA Example 1-2

So, the first array is equal to the word “Welcome,” and the second is equal to the word “to.” Finally, the third array is equal to the word “VBA.”

Step 5: Now, store these array values in cells.

Code:

Sub ReDim_Example1()

  Dim MyArray() As String
  ReDim MyArray(1 To 3)

  MyArray(1) = "Welcome"
  MyArray(2) = "to"
  MyArray(3) = "VBA"

  Range("A1").Value = MyArray(1)
  Range("B1").Value = MyArray(2)
  Range("C1").Value = MyArray(3)

End Sub

Example 1-3

Step 6: If you run this code, we should have these values in A1, B1, and C1 cells, respectively.

Redim Visual basic Application Example 1-4

Example #2 – Resize the Array Size While Remembering the Old Values.

Once the array name is assigned values, we can resize it at any point in the procedure by using the word “ReDim Preserve.”

Assume you have already declared an array name and assigned values to those array names like the below one.

Now, you would like to increase the array length by 2, i.e., 5. In this case, we can use the word VBA “ReDim Preserve” to resize the array length and remember the old values.

Code:

Sub ReDim_Example2()
  
  Dim MyArray() As String
  ReDim MyArray(3)

  MyArray(1) = "Welcome"
  MyArray(2) = "to"
  MyArray(3) = "VBA"

  ReDim Preserve MyArray(4)
  MyArray(4) = "Character 1"

  Range("A1").Value = MyArray(1)
  Range("B1").Value = MyArray(2)
  Range("C1").Value = MyArray(3)
  Range("D1").Value = MyArray(4)

End Sub

Now, we can assign two more values to the array.

Code:

Sub ReDim_Example2()

  Dim MyArray() As String
  ReDim MyArray(3)

  MyArray(1) = "Welcome"
  MyArray(2) = "to"
  MyArray(3) = "VBA"

  ReDim Preserve MyArray(4)
  MyArray(4) = "Character 1"

  Range("A1").Value = MyArray(1)
  Range("B1").Value = MyArray(2)
  Range("C1").Value = MyArray(3)
  Range("D1").Value = MyArray(4)

End Sub

Now, store these values in cells.

Code:

Sub ReDim_Example2()

  Dim MyArray() As String
  ReDim MyArray(3)

  MyArray(1) = "Welcome"
  MyArray(2) = "to"
  MyArray(3) = "VBA"

  ReDim Preserve MyArray(4)
  MyArray(4) = "Character 1"

  Range("A1").Value = MyArray(1)
  Range("B1").Value = MyArray(2)
  Range("C1").Value = MyArray(3)
  Range("D1").Value = MyArray(4)

End Sub

Now, run the Macro and see what happens.

ReDim Preserve 1

So, we got the new word in the D1 cell.

We need to use the word “Preserve” because the array should remember the old array values in the procedure.

When you ignore the word “Preserve,” it will not remember old values.

Things to Remember Here

  • The ReDim can only hold the last value of the array, not the many values. So, for example, we cannot use the code “ReDim Preserve MyArray(4 to 5)”. Instead, it will throw an error.
  • We cannot ReDim static arrays. When you assign the array size inside the parenthesis, it becomes a static array.
  • Using ReDim, we cannot change the data type. The array can hold whatever data type we have assigned while declaring the array.

Recommended Articles

This article has been a guide to VBA ReDim. Here, we discuss handling dynamic arrays using ReDim Preserve, examples, and a downloadable Excel template. Below are some useful Excel articles related to VBA: –

  • VBA ISNULL
  • VBA Format
  • Delete Row in VBA
  • Excel VBA Subscript Out of Range
  • VBA Max

Сашун

1 / 1 / 0

Регистрация: 13.06.2019

Сообщений: 35

1

Изменение размерности двумерного динамического массива

05.07.2020, 08:41. Показов 3904. Ответов 8

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Доброе утро, уважаемые форумчане!
Помогите пожалуйста!
В прикрепленном файле пример изменения размерности двумерного динамического массива
на строке:

Visual Basic
1
ReDim Preserve Ar(UBound(Ar, 1) + 1, 4)

выдает ошибку 9: out of range
Не могу понять почему.
Не могли бы Вы помочь?
Заранее благодарен!

Вложения

Тип файла: 7z test1.7z (10.9 Кб, 4 просмотров)



0



1 / 1 / 0

Регистрация: 13.06.2019

Сообщений: 35

05.07.2020, 08:55

 [ТС]

2

Up
Нашел вот это…
«Переопределить с оператором Preserve можно только последнюю размерность динамического массива. Это недоработка разработчиков, которая сохранилась и в VBA Excel 2016. Без оператора Preserve можно переопределить все размерности.»

Может кто-нибудь подсказать, как можно обойти проблему?

Upd
решено, всем спасибо за участие =)



0



es geht mir gut

11264 / 4746 / 1183

Регистрация: 27.07.2011

Сообщений: 11,437

05.07.2020, 09:21

3

Цитата
Сообщение от Сашун
Посмотреть сообщение

решено,

Как решено ?



0



Сашун

1 / 1 / 0

Регистрация: 13.06.2019

Сообщений: 35

05.07.2020, 09:38

 [ТС]

4

Поскольку у меня массив двумерный, то я тупо поменял местами строки и столбцы

вместо

Visual Basic
1
Redim Preserve Ar(Ubound(Ar, 1) + 1, 4)

я сделал

Visual Basic
1
Redim Preserve Ar(4, Ubound(Ar, 2) + 1)

Но это паллиатив, конечно… Костыль. Что делать в случае многомерных массивов не знаю…



1



Наивное Существо

666 / 141 / 27

Регистрация: 09.05.2020

Сообщений: 750

Записей в блоге: 15

05.07.2020, 09:49

5

Цитата
Сообщение от Сашун
Посмотреть сообщение

«Переопределить с оператором Preserve можно только последнюю размерность динамического массива.

Это всё верно.
Просто сразу продумывайте логику массива.
В принципе, при правильном подходе к этой задаче, мне всегда удавалось обойти указанное ограничение .

Добавлено через 3 минуты
Всё это правильно

Цитата
Сообщение от Сашун
Посмотреть сообщение

«Переопределить с оператором Preserve можно только последнюю размерность динамического массива.

Просто сразу продумывайте логику своего массива.
В принципе, при правильном подходе к задаче, мне всегда удвалось обойти это ограничение.

Цитата
Сообщение от Сашун
Посмотреть сообщение

Поскольку у меня массив двумерный, то я тупо поменял местами строки и столбцы
вместо
Visual BasicВыделить код
1
Redim Preserve Ar(Ubound(Ar, 1) + 1, 4)
я сделал
Visual BasicВыделить код
1
Redim Preserve Ar(4, Ubound(Ar, 2) + 1)



0



passedbyz

Заблокирован

05.07.2020, 09:49

6

Цитата
Сообщение от Сашун
Посмотреть сообщение

Что делать в случае многомерных массивов не знаю…

Делать новый массив и по элементику переносить данные из старого массива в новый.

Цитата
Сообщение от Сашун
Посмотреть сообщение

Это недоработка разработчиков, которая сохранилась и в VBA Excel 2016.

Это не недоработка. Такова суть массивов — добавлять безболезненно можно только в конец, иначе без массовых сдвигов данных ничего не выйдет.



0



1 / 1 / 0

Регистрация: 13.06.2019

Сообщений: 35

05.07.2020, 09:51

 [ТС]

7

Цитата
Сообщение от vedunasv
Посмотреть сообщение

Просто сразу продумывайте логику массива.
В принципе, при правильном подходе к этой задаче, мне всегда удавалось обойти указанное ограничение .

Не знал раньше. Теперь буду учитывать.



0



Наивное Существо

666 / 141 / 27

Регистрация: 09.05.2020

Сообщений: 750

Записей в блоге: 15

05.07.2020, 10:04

8

сообщение продублировалось….эээххххх…
Вы правильно сделали.

Добавлено через 2 минуты
И кстати,

Цитата
Сообщение от vedunasv
Посмотреть сообщение

Preserve

не обязательно указывать. Этот ключ просто позволяет сохранить предыдущие данные. На размер массива он не влияет. Т олько команда REDIM.

Добавлено через 3 минуты
Сашун, Вот видите как всё прекрасно в этом мире…

Добавлено через 15 секунд
Сашун, Вот видите как всё прекрасно в этом мире…

Добавлено через 6 минут
Сашун, а если очень припечёт, я делаю два массива. Конечно, это усложняет анализ. Но ведь в любой БД так и есть — куча массивов полей.



0



1813 / 1135 / 346

Регистрация: 11.07.2014

Сообщений: 4,002

06.07.2020, 17:24

9

Сашун, я понимаю, что очень красиво выглядит ReDim Preserve, но если заранее можно предположить, что число строк буде меньше какого-то значения, если речь не идёт о миллионах, То просто задать статический массив с большим (ударение на первом слоге) числом строк, мы же программисты, люди с широкой душой, и чужой памяти не жалеем. И тогда в некий счетчик заносить число заполненных строк. И проблема увеличения массива по первому измерению пропадает. Чем не вариант?



0



Понравилась статья? Поделить с друзьями:
  • Vba excel рассчитать формулу
  • Vba excel раскрывающийся список
  • Vba excel рамки ячейки
  • Vba excel рамки ячеек
  • Vba excel разъединить ячейки в excel