Vba excel массивы циклы

Цикл For Each… Next в VBA Excel, его синтаксис и описание отдельных компонентов. Примеры использования цикла For Each… Next.

Цикл For Each… Next в VBA Excel предназначен для выполнения блока операторов по отношению к каждому элементу из группы элементов (диапазон, массив, коллекция). Этот замечательный цикл применяется, когда неизвестно количество элементов в группе и их индексация, в противном случае, более предпочтительным считается использование цикла For…Next.

For Each element In group

    [ statements ]

    [ Exit For ]

    [ statements ]

Next [ element ]

В квадратных скобках указаны необязательные атрибуты цикла For Each… Next.

Компоненты цикла For Each… Next

Компонент Описание
element Обязательный атрибут в операторе For Each, необязательный атрибут в операторе Next. Представляет из себя переменную, используемую для циклического прохода элементов группы (диапазон, массив, коллекция), которая предварительно должна быть объявлена с соответствующим типом данных*.
group Обязательный атрибут. Группа элементов (диапазон, массив, коллекция), по каждому элементу которой последовательно проходит цикл For Each… Next.
statements Необязательный** атрибут. Операторы вашего кода.
Exit For Необязательный атрибут. Оператор выхода из цикла до его окончания.

*Если цикл For Each… Next используется в VBA Excel для прохождения элементов коллекции (объект Collection) или массива, тогда переменная element должна быть объявлена с типом данных Variant, иначе цикл работать не будет.

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

Примеры циклов For Each… Next

Цикл для диапазона ячеек

На активном листе рабочей книги Excel выделите диапазон ячеек и запустите на выполнение следующую процедуру:

Sub test1()

Dim element As Range, a As String

  a = «Данные, полученные с помощью цикла For Each… Next:»

    For Each element In Selection

      a = a & vbNewLine & «Ячейка « & element.Address & _

      » содержит значение: « & CStr(element.Value)

    Next

  MsgBox a

End Sub

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

Цикл для коллекции листов

Скопируйте следующую процедуру VBA в стандартный модуль книги Excel:

Sub test2()

Dim element As Worksheet, a As String

  a = «Список листов, содержащихся в этой книге:»

    For Each element In Worksheets

      a = a & vbNewLine & element.Index _

      & «) « & element.Name

    Next

  MsgBox a

End Sub

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

Цикл для массива

Присвоим массиву список наименований животных и в цикле For Each… Next запишем их в переменную a. Информационное окно MsgBox выведет список наименований животных из переменной a.

Sub test3()

Dim element As Variant, a As String, group As Variant

group = Array(«бегемот», «слон», «кенгуру», «тигр», «мышь»)

‘или можно присвоить массиву значения диапазона ячеек

‘рабочего листа, например, выбранного: group = Selection

a = «Массив содержит следующие значения:» & vbNewLine

  For Each element In group

    a = a & vbNewLine & element

  Next

MsgBox a

End Sub

Повторим ту же процедуру VBA, но всем элементам массива в цикле For Each… Next присвоим значение «Попугай». Информационное окно MsgBox выведет список наименований животных, состоящий только из попугаев, что доказывает возможность редактирования значений элементов массива в цикле For Each… Next.

Sub test4()

Dim element As Variant, a As String, group As Variant

group = Array(«бегемот», «слон», «кенгуру», «тигр», «мышь»)

‘или можно присвоить массиву значения диапазона ячеек

‘рабочего листа, например, выделенного: group = Selection

a = «Массив содержит следующие значения:» & vbNewLine

  For Each element In group

    element = «Попугай»

    a = a & vbNewLine & element

  Next

MsgBox a

End Sub

Этот код, как и все остальные в этой статье, тестировался в Excel 2016.

Цикл для коллекции подкаталогов и выход из цикла

В этом примере мы будем добавлять в переменную a названия подкаталогов на диске C вашего компьютера. Когда цикл дойдет до папки Program Files, он добавит в переменную a ее название и сообщение: «Хватит, дальше читать не буду! С уважением, Ваш цикл For Each… Next.».

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

Sub test5()

Dim FSO As Object, myFolders As Object, myFolder As Object, a As String

‘Создаем новый FileSystemObject и присваиваем его переменной «FSO»

Set FSO = CreateObject(«Scripting.FileSystemObject»)

‘Извлекаем список подкаталогов на диске «C» и присваиваем

‘его переменной «myFolders»

Set myFolders = FSO.GetFolder(«C:»)

a = «Папки на диске C:» & vbNewLine

‘Проходим циклом по списку подкаталогов и добавляем в переменную «a«

‘их имена, дойдя до папки «Program Files«, выходим из цикла

  For Each myFolder In myFolders.SubFolders

    a = a & vbNewLine & myFolder.Name

    If myFolder.Name = «Program Files» Then

      a = a & vbNewLine & vbNewLine & «Хватит, дальше читать не буду!» _

      & vbNewLine & vbNewLine & «С уважением,» & vbNewLine & _

      «Ваш цикл For Each... Next.«

  Exit For

    End If

  Next

Set FSO = Nothing

MsgBox a

End Sub

Информационное окно MsgBox выведет список наименований подкаталогов на диске C вашего компьютера до папки Program Files включительно и сообщение цикла о прекращении своей работы.

В результате работы программы будут выведены не только наименования подкаталогов, видимых при переходе в проводнике к диску C, но и скрытые и служебные папки. Для просмотра списка всех подкаталогов на диске C, закомментируйте участок кода от If до End If включительно и запустите выполнение процедуры в редакторе VBA Excel.


I’ll show you how to loop through an array in VBA and macros in Excel.  This is a fairly simple concept but it can be a little tricky.

First, I’m assuming you already know what an array is and how to create and array in VBA [LINK to Article]. Now, that you know that, let’s get to looping though arrays.

There are two main ways to loop through all of the elements of an array in VBA and both of those will be covered below.

Create the Array

First, we need to create an array, and then we can loop through it.

myarray = Array("red", "green", "blue")

Loop through Array Method 1 — LBound and UBound Method

We use this code to loop though the array:

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

    MsgBox "Array value: " & myarray(i)

Next i

The MsgBox part of this code is simply what creates output so that we can see that this loop is working.

The actual loop is just this part:

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

                'inside the loop

Next i

To get this loop to work with your array, you simply need to replace myarray with the name of your array.  If you want a more detailed explanation of everything, continue reading.

There are a few things going on here, so let’s start first with LBound and UBound.

LBound is a function in VBA that will find the lowest point of the array.  This generates a number equal to the lowest index key for the array.  The array that you want this to work on is put within this function, in this case, myarray.

UBound is a function in VBA that will find the highest point of the array.  It outputs a number equal to the highest index key for the array. The array that you want this to work on is put within this function, in this case, myarray.

Now, we use these two functions within a basic For Next loop.

The For Next loop does this:

It sets a variable, in this case i (but it could be any name you want), equal to the LBound function’s output.  Then, it says that this loop should continue running up to when it gets to the number provided by the UBound function, which will be the last index number in the array.

You need to close the loop with Next and then the variable i so that it will continue the loop, adding 1 each time.

Accessing Data from the Array within the Loop

You need to be able to get the data from the array variable and here is how you do it using this method:

While inside the loop, you put the name of your array and then inside parenthesis you put i or whichever variable you used in the loop in place of i; this will get the output from the array within the loop.

Download the accompanying workbook and test out the loop to see how it works.  The result of running this loop is that three message boxes will open and show you the data that is stored in the array variable.  This loop is contained in the macro titled ArrayCreateLoop_1.

Loop through Array Method 2 — For Each …Next Loop Method

 Using the For Each …Next method, we use this code to loop through the array:

For Each element In myarray

    MsgBox "Array value: " & element

Next element

The name of the array is myarray and, in the middle of the loop, we have a line that starts with MsgBox that will output the contents of the array into a message box.

All you need to do to make this loop work for you is to change myarray to the name of your array variable.

If you want to learn more about the loop, keep reading.

This is the actual loop:

For Each element In myarray

                'inside the loop

Next element

This loop will go through every part of the array and put it into a variable that we supply, in this case, the element variable.

You can name this variable whatever you want, you don’t have to call it «element».  If you rename this, make sure to rename it in both paces, after where it says «For Each» and after «Next» — the «Next» part of the loop is what makes this a loop and tells the code to keep going through the variable until it is finished.

Accessing Data from the Array within the Loop

This is very easy to do using this method, simply use the variable that we used in the For Each loop, in this case element.

Anywhere you put this in the loop, the contents of the array will appear.  You can see above how this was used in the line that starts with Msgbox.

Download the accompanying workbook and test out the loop to see how it works.  The result of running this loop is that three message boxes will open and show you the data that is stored in the array variable.  This loop is contained in the macro titled ArrayCreateLoop_2.

Notes

Both of these methods will work just fine for looping though a basic one dimensional array.  For basic arrays, I would use the For Each loop since its syntax is quite a bit easier to understand and use.

However, don’t forget the LBound UBound method because you will often come across it when working with macros in Excel and it works great with more complex array functions.

Also, don’t forget to download the accompanying workbook so you can look at the code and play with it.

Similar Content on TeachExcel

Loop through All Worksheets in Excel using VBA and Macros

Tutorial: Ill show you how to loop through all of the worksheets in a workbook in Excel using VBA an…

Excel VBA — Create an Array — 3 ways

Tutorial: Ill show you three different ways to create an array in Excel VBA and Macros and how to ge…

How to Add a New Line to a Message Box (MsgBox) in Excel VBA Macros

Tutorial: I’ll show you how to create a message box popup window in Excel that contains text on mult…

Loop through a Range of Cells in Excel VBA/Macros

Tutorial: How to use VBA/Macros to iterate through each cell in a range, either a row, a column, or …

Data Validation List with Dynamic Arrays in Excel

Tutorial:
How to make a drop down menu list using data validation and dynamic arrays in Excel 365.

Select Cells in Excel using Macros and VBA

Tutorial: This is actually a very easy thing to do and only requires a couple lines of code. Below I…

Subscribe for Weekly Tutorials

BONUS: subscribe now to download our Top Tutorials Ebook!

Return to VBA Code Examples

In this Article

  • For Each Item in Array
  • For Next Loop
    • Loop Through Part of Array
    • Loop Through Entire Array

This tutorial will teach you how to loop through Arrays in VBA.

There are two primary ways to loop through Arrays using VBA:

  • For Each Loop – The For Each Loop will loop through each item in the array.
  • For Next Loop – The For Next Loop will loop through specified start and end positions of the array (We can use the UBound and LBound Functions to loop through the entire array).

For Each Item in Array

The For Each Loop enables you to loop through each element of the array.

Sub LoopForArrayStatic() 
   'declare a variant array 
   Dim strNames(1 To 4) As String 

   'populate the array 
   strNames(1) = "Bob"
   strNames(2) = "Peter" 
   strNames(3) = "Keith" 
   strNames(4) = "Sam" 

   'declare a variant to hold the array element 
   Dim item as variant

   'loop through the entire array
   For Each item in strNames 
      'show the element in the debug window.
      Debug.Print item
   Next item
End Sub

The above procedure will loop through all the names in the array.

vba array loop 2

For Next Loop

The For Next Loop will loop through each item at a specified start and end position of the array.

Loop Through Part of Array

You can manually specify the start and end positions for your loop. This may be appropriate if you know your array size and/or you only want to loop through part of an array.

Sub LoopForNextStatic()
'declare a variant array
   Dim strNames(1 To 4) As String
'populate the array
   strNames(1) = "Bob"
   strNames(2) = "Peter"
   strNames(3) = "Keith"
   strNames(4) = "Sam"
'declare an integer
   Dim i As Integer
'loop from position 2 to position 3 of the array
   For i = 2 To 3
'show the name in the immediate window
      Debug.Print strNames(i)
   Next i
End Sub

In the example above, we have looped through positions 2 and 3 of the array.  The immediate window would return the names as follows.

vba array loop 1

Loop Through Entire Array

Next, we will use the UBound and LBound Functions to loop through an entire array. This is extremely useful if the start and end positions of the array might change (ex. a Dynamic Array):

Sub LoopForNextDynamic()
'declare a variant array
   Dim strNames() As String
'initialize the array
   ReDim strNames(1 to 4)
'populate the array
   strNames(1) = "Bob"
   strNames(2) = "Peter"
   strNames(3) = "Keith"
   strNames(4) = "Sam"
'declare an integer
   Dim i As Integer
'loop from the lower bound of the array to the upper bound of the array - the entire array
   For i = LBound(strNames) To UBound(strNames)
'show the name in the immediate window
      Debug.Print strNames(i)
   Next i
End Sub

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!

На чтение 24 мин. Просмотров 90.7k.

VBA Arrays

Дональд Кнут

Список настолько же силен, как и его самое слабое звено

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

Содержание

  1. Краткое руководство по массивам VBA
  2. Введение
  3. Быстрые заметки
  4. Что такое массивы и зачем они нужны?
  5. Типы массивов VBA
  6. Объявление массива
  7. Присвоение значений массиву
  8. Использование функций Array и Split
  9. Использование циклов с массивами
  10. Использование Erase
  11. ReDim с Preserve
  12. Сортировка массива
  13. Передача массива в Sub или функцию
  14. Возвращение массива из функции
  15. Двумерные массивы
  16. Чтение из диапазона ячеек в массив
  17. Как заставить ваши макросы работать на суперскорости
  18. Заключение

Краткое руководство по массивам VBA

Задача Статический
массив
Динамический
массив
Объявление Dim arr(0 To 5) As
Long
Dim arr() As Long
Dim arr As Variant
Установить размер Dim arr(0 To 5) As
Long
ReDim arr(0 To 5)As
Variant
Увеличить размер
(сохранить
существующие
данные)
Только
динамический
ReDim Preserve arr(0 To 6)
Установить
значения
arr(1) = 22 arr(1) = 22
Получить значения total = arr(1) total = arr(1)
Первая позиция LBound(arr) LBound(arr)
Последняя позиция Ubound(arr) Ubound(arr)
Читать все записи (1D) For i = LBound(arr) To UBound(arr)
Next i
Or
For i = LBound(arr,1) To UBound(arr,1)
Next i
For i = LBound(arr) To UBound(arr)
Next i
Or
For i = LBound(arr,1) To UBound(arr,1)
Next i
Читать все записи (2D) For i = LBound(arr,1) To UBound(arr,1)
  For j = LBound(arr,2) To UBound(arr,2)
  Next j
Next i
For i = LBound(arr,1) To UBound(arr,1)
  For j = LBound(arr,2) To UBound(arr,2)
  Next j
Next i
Читать все записи Dim item As Variant
For Each item In arr
Next item
Dim item As Variant
For Each item In arr
Next item
Перейти на Sub Sub MySub(ByRef arr() As String) Sub MySub(ByRef arr() As String)
Возврат из функции Function GetArray() 
As Long()
    Dim arr(0 To 5) As
Long
    GetArray = arr
End Function
Function GetArray() 
As Long()
    Dim arr() As Long
    GetArray = arr
End Function
Получить от
функции
Только
динамический
Dim arr() As Long 
Arr = GetArray()
Стереть массив Erase arr
*Сбрасывает все
значения по
умолчанию
Erase arr
*Удаляет массив
Строка в массив Только
динамический
Dim arr As Variant
arr = Split(«James:Earl:Jones»,»:»)
Массив в строку Dim sName As String
sName = Join(arr, «:»)
Dim sName As String
sName = Join(arr, «:»)
Заполните
значениями
Только
динамический
Dim arr As Variant
arr = Array(«John», «Hazel», «Fred»)
Диапазон в массив Только
динамический
Dim arr As Variant
arr = Range(«A1:D2»)
Массив в диапазон Так же, как в
динамическом
Dim arr As Variant
Range(«A5:D6») = arr

Введение

В этой статье подробно рассматриваются массивы на языке программирования Excel VBA. Она охватывает важные моменты, такие как:

  • Зачем вам массивы
  • Когда вы должны их использовать
  • Два типа массивов
  • Использование более одного измерения
  • Объявление массивов
  • Добавление значений
  • Просмотр всех предметов
  • Супер эффективный способ чтения Range в массив

В первом разделе мы рассмотрим, что такое массивы и зачем они нужны. Вы можете не понимать часть кода в первом разделе. Это нормально. Я буду разбивать на простые термины в следующих разделах статьи.

Быстрые заметки

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

Массивы и циклы идут рука об руку. Наиболее распространенными циклами, которые вы используете с массивами, являются циклы For i и For Each.

Что такое массивы и зачем они нужны?

Массив VBA — это тип переменной. Используется для хранения списков данных одного типа. Примером может быть сохранение списка стран или списка итогов за неделю.

В VBA обычная переменная может хранить только одно значение за раз.

В следующем примере показана переменная, используемая для хранения оценок ученика.

' Может хранить только 1 значение за раз
Dim Student1 As Integer
Student1 = 55

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

В следующем примере у нас есть оценки пяти студентов

VBa Arrays

Мы собираемся прочитать эти отметки и записать их в Immediate Window.

Примечание. Функция Debug.Print записывает значения в Immediate Window. Для просмотра этого окна выберите View-> Immediate Window из меню (сочетание клавиш Ctrl + G).

ImmediateWindow

ImmediateSampeText

Как видите в следующем примере, мы пишем один и тот же код пять раз — по одному для каждого учащегося.

Public Sub StudentMarks()

    With ThisWorkbook.Worksheets("Лист1")

        ' Объявите переменную для каждого студента
        Dim Student1 As Integer
        Dim Student2 As Integer
        Dim Student3 As Integer
        Dim Student4 As Integer
        Dim Student5 As Integer

        ' Читайте оценки студентов из ячейки
        Student1 = .Range("C2").Offset(1)
        Student2 = .Range("C2").Offset(2)
        Student3 = .Range("C2").Offset(3)
        Student4 = .Range("C2").Offset(4)
        Student5 = .Range("C2").Offset(5)

        ' Печать студенческих оценок
        Debug.Print "Оценки студентов"
        Debug.Print Student1
        Debug.Print Student2
        Debug.Print Student3
        Debug.Print Student4
        Debug.Print Student5

    End With

End Sub

Ниже приведен вывод из примера

VBA Arrays

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

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

Public Sub StudentMarksArr()

    With ThisWorkbook.Worksheets("Лист1")

        ' Объявите массив для хранения оценок для 5 студентов
        Dim Students(1 To 5) As Integer

        ' Читайте оценки учеников из ячеек C3: C7 в массив
        Dim i As Integer
        For i = 1 To 5
            Students(i) = .Range("C2").Offset(i)
        Next i

        ' Распечатывать оценки студентов из массива
        Debug.Print "Оценки студентов"
        For i = LBound(Students) To UBound(Students)
            Debug.Print Students(i)
        Next i

    End With

End Sub

Преимущество этого кода в том, что он будет работать для любого количества студентов. Если нам нужно изменить этот код для работы с 1000 студентами, нам нужно всего лишь изменить (от 1 до 5) на (от 1 до 1000) в декларации. В предыдущем примере нам нужно было добавить примерно пять тысяч строк кода.

Давайте проведем быстрое сравнение переменных и массивов. Сначала мы сравним процесс объявления.

 ' Объявляем переменные
        Dim Student As Integer
        Dim Country As String

  ' Объявляем массивы
        Dim Students(1 To 3) As Integer
        Dim Countries(1 To 3) As String

Далее мы сравниваем присвоение значения

    ' присвоить значение переменной
        Student1 = .Cells(1, 1) 

    ' присваивать значение первому элементу в массиве
        Students(1) = .Cells(1, 1)

Наконец, мы смотрим на запись значений

  ' Вывести значение переменной
        Debug.Print Student1

  ' Вывести значение первого студента в массиве
        Debug.Print Students(1)

Как видите, использование переменных и массивов очень похоже.

Важным является тот факт, что массивы используют индекс (также называемый нижним индексом) для доступа к каждому элементу. Это означает, что мы можем легко получить доступ ко всем элементам в массиве, используя цикл For.

Теперь, когда у вас есть представление о том, почему массивы полезны, давайте пройдемся по ним шаг за шагом.

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

В VBA есть два типа массивов:

  1. Статический — массив фиксированного размера.
  2. Динамический — массив, в котором размер задается во время выполнения

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

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

Статический массив объявляется следующим образом

Public Sub DecArrayStatic()

    ' Создать массив с местоположениями 0,1,2,3
    Dim arrMarks1(0 To 3) As Long

    ' По умолчанию от 0 до 3, то есть местоположения 0,1,2,3
    Dim arrMarks2(3) As Long

    ' Создать массив с местоположениями 1,2,3,4,5
    Dim arrMarks1(1 To 5) As Long

    ' Создать массив с местоположениями 2,3,4 'Это редко используется
    Dim arrMarks3(2 To 4) As Long

End Sub

VBA Arrays

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

Если вы не используете все расположения массива, ресурсы тратятся впустую. Если вам нужно больше места, вы можете использовать ReDim, но это по сути создает новый статический массив.

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

Public Sub DecArrayDynamic()

    ' Объявить динамический массив
    Dim arrMarks() As Long

    ' Установите размер массива, когда вы будете готовы
    ReDim arrMarks(0 To 5)

End Sub

Динамический массив не выделяется, пока вы не используете оператор ReDim. Преимущество в том, что вы можете подождать, пока не узнаете количество элементов, прежде чем устанавливать размер массива. Со статическим массивом вы должны указать размер заранее.

Присвоение значений массиву

Чтобы присвоить значения массиву, вы используете номер местоположения (пересечении строки и столбца). Вы присваиваете значение для обоих типов массивов одинаково.

Public Sub AssignValue()

    ' Объявить массив с местоположениями 0,1,2,3
    Dim arrMarks(0 To 3) As Long

    ' Установите значение позиции 0
    arrMarks(0) = 5

    ' становите значение позиции 3
    arrMarks(3) = 46

    ' Это ошибка, так как нет местоположения 4
    arrMarks(4) = 99

End Sub

VBA Array 2

Номер места называется индексом. Последняя строка в примере выдаст ошибку «Индекс вне диапазона», так как в примере массива нет местоположения 4.

Использование функций Array и Split

Вы можете использовать функцию Array для заполнения массива списком элементов. Вы должны объявить массив как тип Variant. Следующий код показывает, как использовать эту функцию.

  Dim arr1 As Variant
    arr1 = Array("Апельсин", "Персик","Груша")

  Dim arr2 As Variant
    arr2 = Array(5, 6, 7, 8, 12)

Arrays VBA

Массив, созданный функцией Array, начнется с нулевого индекса, если вы не используете Option Base 1 в верхней части вашего модуля. Затем он начнется с первого индекса. В программировании, как правило, считается плохой практикой иметь ваши реальные данные в коде. Однако иногда это полезно, когда вам нужно быстро протестировать некоторый код. Функция Split используется для разделения строки на массив на основе разделителя. Разделитель — это символ, такой как запятая или пробел, который разделяет элементы.

Следующий код разделит строку на массив из трех элементов.

 Dim s As String
    s = "Красный,Желтый,Зеленый,Синий"

    Dim arr() As String
    arr = Split(s, ",")

Arrays VBA

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

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

Использование цикла For обеспечивает быстрый доступ ко всем элементам массива. Вот где сила использования массивов становится очевидной. Мы можем читать массивы с десятью значениями или десятью тысячами значений, используя те же несколько строк кода. В VBA есть две функции: LBound и UBound. Эти функции возвращают самый маленький и самый большой индекс в массиве. В массиве arrMarks (от 0 до 3) LBound вернет 0, а UBound вернет 3.

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

Public Sub ArrayLoops()

    ' Объявить массив
    Dim arrMarks(0 To 5) As Long

    ' Заполните массив случайными числами
    Dim i As Long
    For i = LBound(arrMarks) To UBound(arrMarks)
        arrMarks(i) = 5 * Rnd
    Next i

    ' Распечатайте значения в массиве
    Debug.Print "Место нахождения", "Значение"
    For i = LBound(arrMarks) To UBound(arrMarks)
        Debug.Print i, arrMarks(i)
    Next i

End Sub

Функции LBound и UBound очень полезны. Их использование означает, что наши циклы будут работать правильно с любым размером массива. Реальное преимущество заключается в том, что если размер массива изменяется, нам не нужно менять код для печати значений. Цикл будет работать для массива любого размера, пока вы используете эти функции.

Использование цикла For Each

Вы можете использовать цикл For Each с массивами. Важно помнить, что он доступен только для чтения. Это означает, что вы не можете изменить значение в массиве.

В следующем коде значение метки изменяется, но оно не меняет значение в массиве.

 For Each mark In arrMarks
        ' Не изменит значение массива
        mark = 5 * Rnd
    Next mark

Цикл For Each отлично подходит для чтения массива. Как видите, лучше писать специально для двумерного массива.

  Dim mark As Variant
    For Each mark In arrMarks
        Debug.Print mark
    Next mark

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

Функция Erase может использоваться для массивов, но она работает по-разному в зависимости от типа массива.

Для статического массива функция Erase сбрасывает все значения по умолчанию. Если массив состоит из целых чисел, то все значения устанавливаются в ноль. Если массив состоит из строк, то все строки устанавливаются в «» и так далее.

Для динамического массива функция удаления стирает память. То есть она удаляет массив. Если вы хотите использовать его снова, вы должны использовать ReDim для выделения памяти.

Давайте рассмотрим пример статического массива. Этот пример аналогичен примеру ArrayLoops в последнем разделе с одним отличием — мы используем Erase после установки значений. Когда значение будет распечатано, все они будут равны нулю.

Public Sub EraseStatic()

    ' Объявить массив
    Dim arrMarks(0 To 3) As Long

    ' Заполните массив случайными числами
    Dim i As Long
    For i = LBound(arrMarks) To UBound(arrMarks)
        arrMarks(i) = 5 * Rnd
    Next i

    ' ВСЕ ЗНАЧЕНИЯ УСТАНОВЛЕНЫ НА НОЛЬ
    Erase arrMarks

    ' Распечатайте значения - там все теперь ноль
    Debug.Print "Место нахождения", "Значение"
    For i = LBound(arrMarks) To UBound(arrMarks)
        Debug.Print i, arrMarks(i)
    Next i

End Sub

Теперь мы попробуем тот же пример с динамикой. После того, как мы используем Erase, все места в массиве были удалены. Нам нужно использовать ReDim, если мы хотим использовать массив снова.

Если мы попытаемся получить доступ к членам этого массива, мы получим ошибку «Индекс вне диапазона».

Public Sub EraseDynamic()

    ' Объявить массив
    Dim arrMarks() As Long
    ReDim arrMarks(0 To 3)

    ' Заполните массив случайными числами
    Dim i As Long
    For i = LBound(arrMarks) To UBound(arrMarks)
        arrMarks(i) = 5 * Rnd
    Next i

    ' arrMarks теперь освобожден. Места не существуют.
    Erase arrMarks

End Sub

ReDim с Preserve

Если мы используем ReDim для существующего массива, то массив и его содержимое будут удалены.

В следующем примере второй оператор ReDim создаст совершенно новый массив. Исходный массив и его содержимое будут удалены.

Sub UsingRedim()

    Dim arr() As String
    
    ' Установить массив в слоты от 0 до 2
    ReDim arr(0 To 2)
    arr(0) = "Яблоко"
    
    ' Массив с яблоком теперь удален
    ReDim arr(0 To 3)

End Sub

Если мы хотим расширить размер массива без потери содержимого, мы можем использовать ключевое слово Preserve.

Когда мы используем Redim Preserve, новый массив должен начинаться с того же начального размера, например мы не можем сохранить от (0 до 2) до (от 1 до 3) или до (от 2 до 10), поскольку они являются различными начальными размерами.

В следующем коде мы создаем массив с использованием ReDim, а затем заполняем массив типами фруктов.

Затем мы используем Preserve для увеличения размера массива, чтобы не потерять оригинальное содержимое.

Sub UsingRedimPreserve()

    Dim arr() As String
    
    ' Установить массив в слоты от 0 до 1
    ReDim arr(0 To 2)
    arr(0) = "Яблоко"
    arr(1) = "Апельсин"
    arr(2) = "Груша"
    
    ' Изменение размера и сохранение исходного содержимого
    ReDim Preserve arr(0 To 5)

End Sub

Из приведенных ниже снимков экрана видно, что исходное содержимое массива было «сохранено».

VBA Preserve

VBA Preserve

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

Использование Preserve с 2-мерными массивами

Preserve работает только с верхней границей массива.

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

Sub Preserve2D()

    Dim arr() As Long
    
    ' Установите начальный размер
    ReDim arr(1 To 2, 1 To 5)
    
    ' Изменить размер верхнего измерения
    ReDim Preserve arr(1 To 2, 1 To 10)

End Sub

Если мы попытаемся использовать Preserve на нижней границе, мы получим ошибку «Индекс вне диапазона».

В следующем коде мы используем Preserve для первого измерения. Запуск этого кода приведет к ошибке «Индекс вне диапазона»:

Sub Preserve2DError()

    Dim arr() As Long
    
    ' Установите начальный размер
    ReDim arr(1 To 2, 1 To 5)
    
    ' Ошибка «Вне диапазона»
    ReDim Preserve arr(1 To 5, 1 To 5)

End Sub

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

Применяются те же правила сохранения. Мы можем использовать Preserve только на верхней границе, как показано в следующем примере:

Sub Preserve2DRange()

    Dim arr As Variant
    
    ' Назначить диапазон массиву
    arr = Sheet1.Range("A1:A5").Value
    
    ' Preserve будет работать только на верхней границе
    ReDim Preserve arr(1 To 5, 1 To 7)

End Sub

Сортировка массива

В VBA нет функции для сортировки массива. Мы можем отсортировать ячейки листа, но это медленно, если данных много.

Функция быстрой сортировки ниже может использоваться для сортировки массива.

Sub QuickSort(arr As Variant, first As Long, last As Long)
  
  Dim vCentreVal As Variant, vTemp As Variant
  
  Dim lTempLow As Long
  Dim lTempHi As Long
  lTempLow = first
  lTempHi = last
  
  vCentreVal = arr((first + last) / 2)
  Do While lTempLow <= lTempHi
  
    Do While arr(lTempLow) < vCentreVal And lTempLow < last
      lTempLow = lTempLow + 1
    Loop
    
    Do While vCentreVal < arr(lTempHi) And lTempHi > first
      lTempHi = lTempHi - 1
    Loop
    
    If lTempLow <= lTempHi Then
    
        ' Поменять значения
        vTemp = arr(lTempLow)

        arr(lTempLow) = arr(lTempHi)
        arr(lTempHi) = vTemp
      
        ' Перейти к следующим позициям
        lTempLow = lTempLow + 1
        lTempHi = lTempHi - 1
      
    End If
    
  Loop
  
  If first < lTempHi Then QuickSort arr, first, lTempHi
  If lTempLow < last Then QuickSort arr, lTempLow, last
  
End Sub

Вы можете использовать эту функцию так:

Sub TestSort()

    ' Создать временный массив
    Dim arr() As Variant
    arr = Array("Банан", "Дыня", "Персик", "Слива", "Яблоко")
  
    ' Сортировать массив
    QuickSort arr, LBound(arr), UBound(arr)

    ' Печать массива в Immediate Window(Ctrl + G)
    Dim i As Long
    For i = LBound(arr) To UBound(arr)
        Debug.Print arr(i)
    Next i

End Sub

Передача массива в Sub или функцию

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

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

 Примечание. Когда вы используете массив в качестве параметра, он не может использовать ByVal, он должен использовать ByRef. Вы можете передать массив с помощью ByVal, сделав параметр вариантом.

' Передает массив в функцию
Public Sub PassToProc()
    Dim arr(0 To 5) As String
    ' Передать массив в функцию
    UseArray arr
End Sub

Public Function UseArray(ByRef arr() As String)
    ' Использовать массив
    Debug.Print UBound(arr)
End Function

Возвращение массива из функции

Важно помнить следующее. Если вы хотите изменить существующий массив в процедуре, вы должны передать его как параметр, используя ByRef (см. Последний раздел). Вам не нужно возвращать массив из процедуры.

Основная причина возврата массива — это когда вы используете процедуру для создания нового. В этом случае вы присваиваете возвращаемый массив массиву в вызывающей программе. Этот массив не может быть уже выделен. Другими словами, вы должны использовать динамический массив, который не был выделен.

Следующие примеры показывают это:

Public Sub TestArray()

    ' Объявить динамический массив - не выделен
    Dim arr() As String
    ' Возврат нового массива
    arr = GetArray

End Sub

Public Function GetArray() As String()

    ' Создать и выделить новый массив
    Dim arr(0 To 5) As String
    ' Возвращаемый массив
    GetArray = arr

End Function

Двумерные массивы

Массивы, на которые мы смотрели до сих пор, были одномерными. Это означает, что массивы представляют собой один список элементов.

Двумерный массив — это список списков. Если вы думаете об одной строке электронной таблицы как об одном измерении, то более одного столбца является двухмерным. На самом деле электронная таблица является эквивалентом двумерного массива. Он имеет два измерения — строки и столбцы.

Следует отметить одну маленькую вещь: Excel обрабатывает одномерный массив как строку, если вы записываете его в электронную таблицу. Другими словами, массив arr (от 1 до 5) эквивалентен arr (от 1 до 1, от 1 до 5) при записи значений в электронную таблицу.

На следующем рисунке показаны две группы данных. Первый — это одномерный массив, а второй — двухмерный.

VBA Array Dimension

Чтобы получить доступ к элементу в первом наборе данных (одномерном), все, что вам нужно сделать, это дать строку, например. 1,2, 3 или 4.

Для второго набора данных (двумерного) вам нужно указать строку И столбец. Таким образом, вы можете думать, что 1-мерное — это несколько столбцов, а одна строка и двухмерное — это несколько строк и несколько столбцов.

Примечание. В массиве может быть более двух измерений. Это редко требуется. Если вы решаете проблему с помощью 3+-мерного массива, то, вероятно, есть лучший способ сделать это.

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

Dim ArrayMarks(0 To 2, 0 To 3) As Long

В следующем примере создается случайное значение для каждого элемента в массиве и печатается значение в Immediate Window.

Public Sub TwoDimArray()

    ' Объявить двумерный массив
    Dim arrMarks(0 To 3, 0 To 2) As String

    ' Заполните массив текстом, состоящим из значений i и j
    Dim i As Long, j As Long
    For i = LBound(arrMarks) To UBound(arrMarks)
        For j = LBound(arrMarks, 2) To UBound(arrMarks, 2)
            arrMarks(i, j) = CStr(i) & ":" & CStr(j)
        Next j
    Next i

    ' Вывести значения в массиве в Immediate Window
    Debug.Print "i", "j", "Знаечние"
    For i = LBound(arrMarks) To UBound(arrMarks)
        For j = LBound(arrMarks, 2) To UBound(arrMarks, 2)
            Debug.Print i, j, arrMarks(i, j)
        Next j
    Next i

End Sub

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

Результат примера выглядит следующим образом:

VBA Arrays

Этот макрос работает следующим образом:

  • Входит в цикл i
  • i установлен на 0
  • цикл Enters j
  • j установлен на 0
  • j установлен в 1
  • j установлен на 2
  • Выход из цикла j
  • i установлен в 1
  • j установлен на 0
  • j установлен в 1
  • j установлен на 2
  • И так до тех пор, пока i = 3 и j = 2

Заметьте, что LBound и UBound имеют второй аргумент 2. Это указывает, что это верхняя или нижняя граница второго измерения. Это начальное и конечное местоположение для j. Значение по умолчанию 1, поэтому нам не нужно указывать его для цикла i.

Использование цикла For Each

Использование For Each лучше использовать при чтении из массива.
Давайте возьмем код сверху, который выписывает двумерный массив.

 ' Для цикла For необходимо два цикла
    Debug.Print "i", "j", "Значение"
    For i = LBound(arrMarks) To UBound(arrMarks)
        For j = LBound(arrMarks, 2) To UBound(arrMarks, 2)
            Debug.Print i, j, arrMarks(i, j)
        Next j
    Next i

Теперь давайте перепишем его, используя цикл For Each. Как видите, нам нужен только один цикл, и поэтому гораздо проще написать:

 ' Использование For Each требует только одного цикла
    Debug.Print "Значение"
    Dim mark As Variant
    For Each mark In arrMarks
        Debug.Print mark
    Next mark

Использование цикла For Each дает нам массив только в одном порядке — от LBound до UBound. В большинстве случаев это все, что вам нужно.

Чтение из диапазона ячеек в массив

Если вы читали мою статью о ячейках и диапазонах, то вы знаете, что VBA имеет чрезвычайно эффективный способ чтения из диапазона ячеек в массив и наоборот.

Public Sub ReadToArray()

    ' Объявить динамический массив
    Dim StudentMarks As Variant

    ' Считать значения в массив из первой строки
    StudentMarks = Range("A1:Z1").Value

    ' Запишите значения обратно в третий ряд
    Range("A3:Z3").Value = StudentMarks

End Sub

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

В следующем примере будут считаны примеры данных студента ниже из C3: E6 Лист1 и распечатаны в Immediate Window.

Public Sub ReadAndDisplay()

    ' Получить диапазон
    Dim rg As Range
    Set rg = ThisWorkbook.Worksheets("Лист1").Range("C3:E6")

    ' Создать динамический массив
    Dim StudentMarks As Variant

    ' Считать значения в массив из листа 1
    StudentMarks = rg.Value

    ' Вывести значения массива
    Debug.Print "i", "j", "Значение"
    Dim i As Long, j As Long
    For i = LBound(StudentMarks) To UBound(StudentMarks)
        For j = LBound(StudentMarks, 2) To UBound(StudentMarks, 2)
            Debug.Print i, j, StudentMarks(i, j)
        Next j
    Next i

End Sub

VBA 2D Array

VBA 2D Array Output

Как видите, первое измерение (доступное через i) массива — это строка, а второе — столбец. Чтобы продемонстрировать это, взглянем на значение 44 в Е4 данных образца. Это значение находится в строке 2 столбца 3 наших данных. Вы можете видеть, что 44 хранится в массиве в StudentMarks (2,3).

Как заставить ваши макросы работать на суперскорости

Если ваши макросы работают очень медленно, этот раздел будет очень полезным. Особенно, если вы имеете дело с большими объемами данных. В VBA это держится в секрете.

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

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

  1. Скопируйте данные из ячеек в массив.
  2. Измените данные в массиве.
  3. Скопируйте обновленные данные из массива обратно в ячейки.

Например, следующий код будет намного быстрее, чем код ниже:

Public Sub ReadToArray()

    ' Считать значения в массив из первой строки
    Dim StudentMarks  As Variant
    StudentMarks = Range("A1:Z20000").Value

    Dim i As Long
    For i = LBound(StudentMarks) To UBound(StudentMarks)
        ' Обновление отметок здесь
        StudentMarks(i, 1) = StudentMarks(i, 1) * 2
        '...
    Next i

    ' Запишите новые значения обратно на лист
    Range("A1:Z20000").Value = StudentMarks

End Sub
Sub UsingCellsToUpdate()
    
    Dim c As Variant
    For Each c In Range("A1:Z20000")
        c.Value = ' Обновите значения здесь
    Next c
    
End Sub

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

' Назначение - быстрее
Range("A1:A10").Value = Range("B1:B10").Value

' Копировать Вставить - медленнее
Range("B1:B1").Copy Destination:=Range("A1:A10")

Заключение

Ниже приводится краткое изложение основных моментов этой статьи.

  1. Массивы — это эффективный способ хранения списка элементов одного типа.
  2. Вы можете получить доступ к элементу массива напрямую, используя номер местоположения, который известен как индекс.
  3. Распространенная ошибка «Индекс вне диапазона» вызвана доступом к несуществующему местоположению.
  4. Существует два типа массивов: статический и динамический.
  5. Статический используется, когда размер массива всегда одинаков.
  6. Динамические массивы позволяют вам определять размер массива во время выполнения.
  7. LBound и UBound обеспечивают безопасный способ поиска самых маленьких и самых больших подписок массива.
  8. Основной массив является одномерным. Есть еще многомерные массивы.
  9. Чтобы только передать массив в процедуру, используйте ByRef. Вы делаете это так: ByRef arr() as long.
  10. Вы можете вернуть массив из функции, но массив, которому он назначен, не должен быть выделен в данный момент.
  11. Рабочий лист с его строками и столбцами по сути является двумерным массивом.
  12. Вы можете читать непосредственно из диапазона листа в двухмерный массив всего за одну строку кода.
  13. Вы также можете записать из двумерного массива в диапазон всего за одну строку кода.

I have an array of Strings:

Dim sArray(4) as String

I am going through each String in the array:

for each element in sarray
  do_something(element)
next element

do_something takes a string as a parameter

I am getting an error passing the element as a String:

ByRef Argument Mismatch

Should I be converting the element to a String or something?

TylerH's user avatar

TylerH

20.6k64 gold badges76 silver badges97 bronze badges

asked Nov 19, 2010 at 18:22

Alex Gordon's user avatar

Alex GordonAlex Gordon

55.8k284 gold badges666 silver badges1051 bronze badges

1

Element needs to be a variant, so you can’t declare it as a string. Your function should accept a variant if it is a string though as long as you pass it ByVal.

Public Sub example()
    Dim sArray(4) As string
    Dim element As variant

    For Each element In sArray
        do_something element
    Next element
End Sub


Sub do_something(ByVal e As String)
    
End Sub

The other option is to convert the variant to a string before passing it.

  do_something CStr(element)

BigBen's user avatar

BigBen

43.9k6 gold badges27 silver badges40 bronze badges

answered Nov 19, 2010 at 19:27

Bobsickle's user avatar

2

A for each loop structure is more designed around the collection object. A For..Each loop requires a variant type or object. Since your «element» variable is being typed as a variant your «do_something» function will need to accept a variant type, or you can modify your loop to something like this:

Public Sub Example()

    Dim sArray(4) As String
    Dim i As Long

    For i = LBound(sArray) To UBound(sArray)
        do_something sArray(i)
    Next i

End Sub

answered Nov 19, 2010 at 18:51

Fink's user avatar

FinkFink

3,31619 silver badges26 bronze badges

2

I use the counter variable like Fink suggests. If you want For Each and to pass ByRef (which can be more efficient for long strings) you have to cast your element as a string using CStr

Sub Example()

    Dim vItm As Variant
    Dim aStrings(1 To 4) As String

    aStrings(1) = "one": aStrings(2) = "two": aStrings(3) = "three": aStrings(4) = "four"

    For Each vItm In aStrings
        do_something CStr(vItm)
    Next vItm

End Sub

Function do_something(ByRef sInput As String)

    Debug.Print sInput

End Function

answered Nov 19, 2010 at 20:39

Dick Kusleika's user avatar

Dick KusleikaDick Kusleika

32.5k4 gold badges51 silver badges73 bronze badges

what about this simple inArray function:

Function isInArray(ByRef stringToBeFound As String, ByRef arr As Variant) As Boolean
For Each element In arr
    If element = stringToBeFound Then
        isInArray = True
        Exit Function
    End If
Next element
End Function

answered Jun 17, 2014 at 7:24

Sebastian Viereck's user avatar

If alternatives are acceptable for this case, I would rather suggest UBound :

For i = 1 to UBound(nameofthearray)
   your code here
next i

answered Apr 28, 2021 at 23:55

user2922434's user avatar

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