В теме 5.6 мы писали функции с одним-двумя аргументами. Но что делать, если данных не два и не три, а двадцать однотипных значений — двадцать цен, двадцать фамилий? Заводить Цена1, Цена2, … Цена20 неудобно и совсем не годится, когда заранее не известно, сколько их будет. Для этого в VBA есть массив — одна переменная, которая хранит сразу много значений под одним именем, и коллекция — похожая идея, но для готовых объектов Excel: листов, книг, диапазонов.
К концу темы ты сможешь:
— объявить массив, обратиться к его элементу по индексу и заполнить его в цикле;
— объяснить разницу между одномерным и многомерным массивом;
— сделать массив динамическим и понимать, для чего нужен ReDim Preserve;
— перебрать коллекцию объектов Excel через For Each и посчитать её через Count;
— объяснить, чем коллекция принципиально отличается от массива.
Вспомни: в теме 5.2 мы разбирали цикл For…Next. Он и заполняет, и перебирает массивы — без цикла обращаться к каждому элементу по отдельности было бы так же неудобно, как заводить Цена1, Цена2, Цена3.
Зачем нужен массив: объявление, индексы, одномерные и многомерные
Представь: нужно посчитать сумму пяти цен, введённых пользователем. Без массива — пять отдельных переменных Цена1…Цена5 и пять строк кода на каждое действие. С массивом — одна переменная и цикл: та же логика работает для 5 значений и для 500 без единой правки кода.
Массив объявляют как обычную переменную, но с числом в скобках после имени — это верхняя граница индексов. Dim tsena(4) As Double создаёт массив не из четырёх, а из ПЯТИ элементов: по умолчанию нумерация в VBA начинается с нуля, поэтому границы — tsena(0), tsena(1), tsena(2), tsena(3), tsena(4).
Dim tsena(4) As Double
tsena(0) = 120
tsena(1) = 85
tsena(2) = 340
tsena(3) = 60
tsena(4) = 200
Dim tsena(4) As Double -> массив из ПЯТИ элементов (индексы с 0 по умолчанию)
индекс: 0 1 2 3 4
+------+------+------+------+------+
tsena: | 120 | 85 | 340 | 60 | 200 |
+------+------+------+------+------+
Обращение tsena(2) вернёт значение из ТРЕТЬЕЙ по счёту ячейки: 340.
Заполнять и перебирать массив вручную по одному элементу — та же ошибка, что заводить отдельные переменные. Обычно это делают циклом For, где счётчик цикла одновременно служит индексом массива.
Dim i As Integer
Dim summa As Double
For i = 0 To 4
summa = summa + tsena(i)
Next i
Одномерный массив — это список: одна строка значений. Многомерный массив — это уже таблица: например, Dim tab(1, 2) As String создаёт таблицу из 2 строк (индексы 0-1) и 3 столбцов (индексы 0-2). Обращаются к ячейке такой таблицы двумя индексами: сначала строка, потом столбец — tab(0, 0), tab(1, 2) и так далее.
Dim tab(1, 2) As String -> таблица 2 строки x 3 столбца
столбец 0 столбец 1 столбец 2
строка 0 tab(0,0) tab(0,1) tab(0,2)
строка 1 tab(1,0) tab(1,1) tab(1,2)
Первый индекс - строка, второй - столбец. Порядок важен.
Динамический массив: ReDim и ReDim Preserve
Массивы из примеров выше — статические: размер задан один раз в Dim и не меняется. Но заранее не всегда известно, сколько будет значений — например, число заказов за день заранее не знаешь. Для этого массив объявляют динамическим — с пустыми скобками, без числа, — а размер задают позже командой ReDim, уже во время выполнения кода.
Dim zakazy() As String ' массив без размера - динамический
ReDim zakazy(2) ' теперь у него 3 элемента: индексы 0, 1, 2
zakazy(0) = "Заказ №1"
zakazy(1) = "Заказ №2"
zakazy(2) = "Заказ №3"
Проблема в том, что обычный ReDim заново создаёт массив и стирает всё, что в нём уже лежало. Если заказов вдруг стало больше и нужно расширить массив, не потеряв уже записанные значения, используют ReDim Preserve — она меняет размер и сохраняет прежние данные.
ReDim Preserve zakazy(3) ' стало 4 элемента, старые 3 заказа НИКУДА не делись
zakazy(3) = "Заказ №4"
Важное ограничение. Обычный ReDim можно применять к массиву сколько угодно раз в любую сторону. А ReDim Preserve умеет менять размер только у ПОСЛЕДНЕГО измерения массива и не может поменять само количество измерений (одномерный не станет двумерным). Для одномерного массива это не проблема — там измерение всего одно.
Коллекции: готовые наборы объектов и своя коллекция
Массив — это то, что заполняешь сам: числа, строки, любые значения. Коллекция — это уже готовый набор ОБЪЕКТОВ, который предоставляет сам Excel. Например, Worksheets — коллекция всех листов книги, а Workbooks — коллекция всех открытых книг Excel. Каждый элемент такой коллекции — не число и не строка, а целый объект листа или книги со своими свойствами и методами.
Debug.Print Worksheets.Count ' сколько листов в книге
Dim sh As Worksheet
For Each sh In Worksheets
Debug.Print sh.Name ' имя каждого листа по очереди
Next sh
For Each — это специальный вид цикла для перебора коллекций: он не считает индексы сам, а просто на каждом шаге даёт очередной объект коллекции, пока она не закончится. Свойство Count есть у любой коллекции и сразу отвечает на вопрос «сколько там элементов», без ручного подсчёта.
Кроме готовых коллекций Excel, можно завести и свою — для собственного набора объектов или значений, которые ты пополняешь по ходу работы кода. У любой коллекции есть всего четыре основных инструмента: Add — добавить элемент, Remove — убрать, Count — узнать количество, Item — получить элемент по номеру.
Dim goroda As New Collection
goroda.Add "Москва"
goroda.Add "Казань"
goroda.Add "Томск"
Debug.Print goroda.Count ' 3
Dim g As Variant
For Each g In goroda
Debug.Print g
Next g
Обратиться к элементу коллекции по номеру можно через Item: goroda.Item(1) вернёт первый добавленный город. Номер у Item начинается с 1, а не с 0, как у обычного массива — путать эти два индекса легко, если забыть про разницу.
Debug.Print goroda.Item(1) ' первый добавленный город
МАССИВ КОЛЛЕКЦИЯ ─────────────────────────────────────────────────────────────── размер фиксирован в Dim/ReDim растёт сама через .Add, (если не динамический) ужимается через .Remove хранит значения (числа, строки), хранит уже готовые ОБЪЕКТЫ которые кладёшь сам (листы, книги) или свои элементы индексация с 0 по умолчанию нумерация Item обычно с 1 перебор: For i = 0 To ... перебор: For Each элемент In ...
Проверь себя
Контрольный вопрос. Зачем в VBA используют массив вместо отдельных переменных Цена1, Цена2, Цена3…?
Подсказка: Подумай, что придётся переписывать в коде, если значений станет не 5, а 500.
Онлайн-проверка ответа появится позже
Задание. Сколько элементов будет у этого массива? Впиши число.
Исходный код для этого задания:
Dim tsena(4) As DoubleПодсказка: Нумерация по умолчанию начинается с нуля, а не с единицы.
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Контрольный вопрос. С какого индекса по умолчанию начинается нумерация элементов обычного массива в VBA?
Подсказка: Именно поэтому Dim tsena(4) даёт пять элементов, а не четыре.
Онлайн-проверка ответа появится позже
Задание. Что вернёт bukvy(2)? Впиши без кавычек.
Исходный код для этого задания:
Dim bukvy(3) As String bukvy(0) = "А" bukvy(1) = "Б" bukvy(2) = "В" bukvy(3) = "Г"Подсказка: Индекс 2 — это третий по счёту элемент, если считать с нуля.
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Задание. Таблицу заполнили этим двойным циклом. Чему равно значение tab(1, 2)? Впиши число.
Исходный код для этого задания:
Dim tab(1, 2) As Integer Dim i As Integer, j As Integer For i = 0 To 1 For j = 0 To 2 tab(i, j) = i * 10 + j Next j Next iПодсказка: Подставь i=1 (номер строки) и j=2 (номер столбца) в формулу i * 10 + j.
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Как объявить массив так, чтобы его точный размер можно было задать позже, уже во время выполнения кода?
Подсказка: В уроке такой массив назывался динамическим.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Чем ReDim Preserve отличается от обычного ReDim при изменении размера массива?
Подсказка: Подумай, что случится с уже введёнными данными в обоих случаях — это и есть разница.
Онлайн-проверка ответа появится позже
Контрольный вопрос. У массива два измерения: Dim tab(2, 3). Можно ли через ReDim Preserve изменить количество СТРОК (первое измерение), сохранив данные?
Подсказка: В уроке это было отдельно отмечено как ограничение — Preserve трогает только ОДНО измерение, и не первое.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Чем коллекция (например, Worksheets) принципиально отличается от обычного массива?
Подсказка: Массив ты заполняешь сам числами или строками. А кто заполняет Worksheets?
Онлайн-проверка ответа появится позже
Задание. Что выведет код Debug.Print Worksheets.Count? Впиши число.
В книге Excel открыто три листа: «Январь», «Февраль», «Март».
Подсказка: Count у коллекции листов считает, сколько всего листов в книге.
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Что делает конструкция For Each sh In Worksheets … Next sh?
Подсказка: For Each создан специально для обхода коллекций, а не для подсчёта индексов.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Отметь все верные утверждения о коллекциях в VBA (не менее двух вариантов).
Выберите все верные варианты.
Подсказка: Два утверждения приписывают коллекции свойства обычного статического массива.
Онлайн-проверка ответа появится позже
Контрольный вопрос. Какой город вернёт goroda.Item(1)?
Исходный код для этого задания:
Dim goroda As New Collection goroda.Add "Москва" goroda.Add "Казань" goroda.Add "Томск"Подсказка: У Item нумерация начинается с 1, а не с 0 — это первый добавленный элемент.
Онлайн-проверка ответа появится позже
Задание. Что вернёт tovary.Count после выполнения этого кода? Впиши число.
Исходный код для этого задания:
Dim tovary As New Collection tovary.Add "Ноутбук" tovary.Add "Мышь" tovary.Add "Клавиатура" tovary.Add "Монитор" tovary.Remove 2Подсказка: Сначала добавили 4 элемента, потом один убрали методом Remove по номеру.
✅ Готово, если: ты ввёл(а) верный ответ, и онлайн-проверка его приняла.
Онлайн-проверка ответа появится позже
Итог
Итог. Массив хранит много однотипных значений под одним именем; индексация по умолчанию с нуля, Dim arr(4) даёт пять элементов. Одномерный массив — список, многомерный (Dim tab(1,2)) — таблица, где первый индекс строка, второй столбец. Динамический массив объявляют пустыми скобками и задают размер позже через ReDim; ReDim Preserve сохраняет данные при изменении размера, но меняет только последнее измерение. Коллекция (Worksheets, Workbooks или своя через New Collection) хранит готовые объекты, а не значения; Add добавляет элемент, Count считает их количество, For Each перебирает коллекцию без ручного подсчёта индексов.
Практика (необязательная)
Задание для практики. Заведи динамический массив Dim otdely() As String. Через ReDim задай ему размер на 3 элемента и заполни названиями трёх отделов твоей компании (или придуманной). Затем через ReDim Preserve увеличь размер до 4 и добавь ещё один отдел, не потеряв первые три. Выведи все значения через Debug.Print в цикле For. Отдельно заведи Collection, добавь в неё те же названия через Add и выведи их через For Each — сравни, чем этот перебор отличался от перебора массива.
← Назад · ↑ В начало урока · ⌂ В начало курса · Вперёд: Внешние файлы и данные →
