Цикл For Each… Next в VBA Excel, его синтаксис и описание отдельных компонентов. Примеры использования цикла For Each… Next.
Цикл For Each… Next в VBA Excel предназначен для выполнения блока операторов по отношению к каждому элементу из группы элементов (диапазон, массив, коллекция). Этот замечательный цикл применяется, когда неизвестно количество элементов в группе и их индексация, в противном случае, более предпочтительным считается использование цикла For…Next.
Синтаксис цикла For Each… Next
1 2 3 4 5 |
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 выделите диапазон ячеек и запустите на выполнение следующую процедуру:
1 2 3 4 5 6 7 8 9 |
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:
1 2 3 4 5 6 7 8 9 |
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.
1 2 3 4 5 6 7 8 9 10 11 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 |
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.
Здравствуйте!
Я новичок в VBA, поэтому ,возможно, вопрос глупый, но не могу никак придумать процедуру для сравнения двух массивов с помощью цикла For Each… Next.
т.е. имеются столбцы A:B — ФИО1 Дата1 и столбцы C:D — ФИО2 Дата2. Хочу сравнить и при совпадении выделить совпадающие ячейки цветом.
Подскажите, хотя бы примерно, как это сделать.
Спасибо
Здравствуйте!
Диапазоны в примере одинаковые по размеру, но могут быть любые:
Спасибо большое, Евгений!
Я немного неправильно сформулировал.
Нужно выделить, если пары ФИО и Дата совпадают.
т.е. Иванов 1979 и Иванов 1979 выделялись, а Иванов 1979 и Иванов 1980 нет. Так же как и Иванов 1979 и Петров 1979 не нужно выделять.
Пока придумал только если создать дополнительные столбцы и в них прописать «=A1&B1» и по ним сравнивать.
Можно ли как то сделать по другому?
Можно и по-другому, попробуйте так:
Спасибо огромное. То, что нужно!
Добрый день.
Есть задача посложнее.
Лист 1 . А1 инвентарный номер (10 или 12 знаков) . В1 колличество полученных деталей.
Лист 2 . Колонка J содержит инвентарный номер (может быть несколько строк). Колонка S содержит текст внутри которого колличество полученных деталей (B1 листа 1). Колонка N содержит дату получения деталей.
Задача надо найти по данным Листа1 совпадение А1&В1 на Листе 2 данные колонки n
Здравствуйте!
Подскажите пожалуйста, как с помощью цикла For Each…Next можно выполнить задачу:
Есть диапазон со значениями, например («B1:С5»)
Нужно все значения из этого диапазона последовательно вынести в столбец A (раздельно, не в одну ячейку)
Здравствуйте, Дарья!
Большое спасибо!
У вас очень классный сайт, существенно мне помог разобраться в VBA Excel
Добрый день, очень часто пользуюсь информацией с Вашего сайта, но вот тут возникла задача, с которой справиться не получается, возможно вы сможете помочь.
У меня есть массив:
В данном массиве необходимо сравнить каждую ячейку с каждой из этого же массива и найти такую же цифру, только с противоположным знаком, если такой цифры с противоположным знаком нет -> (то вывести в столбик такие цифры, к которым нет противоположных), а если есть цифра с противоположным знаком -> (то ничего делать с ней не нужно).
Здравствуйте, Михаил!
Найденные числа записываются в первый столбец листа «Лист1». Пустые ячейки (нули) игнорируются.
Правильно ли будет отрабатываться условие "если такой цифры с противоположным знаком нет -> (то вывести в столбик такие цифры, к которым нет противоположных)" во втором цикле? Будет ложное срабатывание, когда val1=5 и val2=6, например, ведь 5<>-6.
Привет!
Условие
проверяет, с какими значениями переменных закончился внутренний цикл. Если это 5 и 6, значит в массиве нет значения -5, и это не ложное, а верное срабатывание.
Добрый вечер! Подскажите, пожалуйста, как исправить проблему? Дана строка символов, и нужно определить, встречаются ли в ней 5 символов «$» и 3 символа «%»? Почему-то в любом случае результат, что «Символы не встречаются». Заранее спасибо.
Дарья, объявление переменных
соответствует объявлению
А код измените следующим образом:
Здравствуйте.
Подскажите, пожалуйста, как выполнить задачу. Есть лист1. В нем столбик А с ячейками ID(заранее известно количество строк). Нужно сравнить с ячейками ID столбика А листа2 и при совпадении записать данные из столбика К листа1 в столбик D листа2 вместе с цветом ячейки. В листе2 не известно заранее сколько строк. Я написала начало, дальше не пойму как.
Здравствуйте, Елена!
Как я понял из вашего кода, просмотр начинается с 3 строки. Вот два варианта решения, где вам нужно только заменить Лист11 на Worksheets("22.11-28.11") и Лист12 на второй ваш лист:
Спасибо большое! Первый вариант мне как-то более понятен. Т.е. теперь, чтобы передать цвет ячейки, надо дописать перед выходом из внутреннего цикла
Только это не работает.
Елена, вы правильно написали, надо добавить именно эту строку, и она работает — только что проверил. Может быть, вы в ней не поменяли названия листов?
Да работает. Просто цвета, созданные условным форматированием, не переносятся
Попробуйте
заменить на
Результат не гарантирован, так как он будет зависеть от формулировок правил условного форматирования.
Как-то частично переносит цвет.
Заметила, что и на первом листе и на втором игнорируется последняя строка. Поставила n1 + 1, n2 + 1 и все работает как надо.
Подскажите, пожалуйста,как обозначить выполнение цикла операций после проведения отбора каждого из возможных значений по одному из столбцов?
Есть массив данных(много столбцов) с разными значениями в ячейках столбца День(от 1до 31). Нужно последовательно для каждого дня вывести массив, скопировать его (отдельные части) и перенести в другую книгу. Так для каждого дня. Т.е последовательно скопировать и вставить массивы данных в другую книгу. В общем массиве могут быть не все даты месяца.
Подскажите пожалуйста есть ли способ с помощью этого цикла перекрасить объекты (Shape) имеющие в себе гиперссылки (Hyperlink) во всей книге.
Для листа у меня вышло а для книги не могу понять как, прошу помощи так как только начал разбираться в vba.
Код макроса.
Здравствуйте, Денис!
Ваш код для всей текущей книги:
Здравствуйте. А как быть, если выбраны пользователем несмежные ячейки? Перебор не идёт (
Здравствуйте, Владимир!
У меня цикл
For Each… Next
работает и с выбранными несмежными ячейками —Selection
, и с заданными как объект Range —Range("B4:B5,D7:D8,G1:G2")
. Проверьте у себя еще раз на примере цикла для диапазона ячеек (test1).Здравствуйте.
Я инженер, работаю со сметами. У нас разделы в смете, и после каждого раздела нужна подсчитать итог, разделы начинаются :
" РАЗДЕЛ "НОМЕР" ****** "
. У меня не получается никак. Подскажите пожалуйста.Здравствуйте, Андрей!
Недостаточно информации для понимания ситуации. Объясните структуру сметы: в каком столбце находятся названия разделов, какие диапазоны надо суммировать, куда записывается результат суммирования.
Таблица в столбцах A:H. Раздел находится в столбцах B:F (одна строка) мне нужно суммировать столбец H от первого раздела до следующего раздела ( все разделы по отдельности). Вверху раздела одна пустая строка, там должно вписаться результат суммы раздела в столбце H. Все разделы должны по отдельности суммироваться.
По вашему описанию я представляю так:
Сстрока 1 — шапка таблицы.
Блок раздела 1:
ячейка B2 — наименование раздела (РАЗДЕЛ 1)
диапазон H3-H8 — диапазон суммирования
ячейка H9 — сумма
Блок раздела 2:
ячейка B10 — наименование раздела (РАЗДЕЛ 2)
диапазон H11-H20 — диапазон суммирования
ячейка H21 — сумма
и так далее (диапазон суммирования — величина переменная). Правильно?
Да. Но разделы не
"B2"
а"B2:F2"
то есть они объединены в одну строку (столбцы). Разделы начинаются со слова , например"Раздел 1. Кровля"
, то есть разделы начинается :"Раздел "номер" "****"
. и т.д. Мне нужно пробегаться по этим разделам и вставить итог в конце. Остальное все правильно.Андрей, в объединенной ячейке отображается только значение первой ячейки, поэтому обращаться к объединенной ячейке
"B2:F2"
будем"B2"
. Код будет работать при отсутствии пустых ячеек внутри суммируемых диапазонов, нули допускаются:Привет, Евгений. Ну я вписал, не работает, только n подсчитывает последнюю строку. Сумма в столбце H не вставляется, m тоже не работает.
Андрей, у меня все работает. Возможно, у вас структура таблицы другая.
В строке раздела в столбце «H» пусто.
Структура:
В 1 столбце нумерация.
В 2ом обоснование.
В 3ем наименование.
В 4ем ед.измерение.
В 5ом норма.
В 6ом по проекту.
В 7ом цена
В 8ом сумма.
Если на пересечении строки раздела и столбца «H» пусто, тогда:
Привет Евгений. Можно функцию сумм как формулу ввести, чтобы в ячейке была формула?
Можно и формулу вставить:
Спасибо Евгений, удачи тебе, очень помог!!..
Здравствуйте, по работе нужно модернизировать существующий макрос, чтобы он для ячеек из диапазона столбцов от G до N заполнял пустые ячейки прочерками "-", как я полагаю, используя For Each, можете помочь?
Sub форматированиеПубликации()
Dim ind_sheets As Integer 'индекс листа'
Dim ind_row As Integer 'индекс строки'
Application.ScreenUpdating = False
'форматирование листов с №4 по №17 '
For ind_sheets = 4 To 17 'Sheets.Count'
Sheets(ind_sheets).Activate
ind_row = 8
While ActiveSheet.Cells(ind_row, 2).Value & ActiveSheet.Cells(ind_row, 3).Value & ActiveSheet.Cells(ind_row, 4).Value & ActiveSheet.Cells(ind_row, 5).Value & ActiveSheet.Cells(ind_row, 6).Value & ActiveSheet.Cells(ind_row, 7).Value <> ""
If (ActiveSheet.Cells(ind_row, 2).Value <> "") And (ActiveSheet.Cells(ind_row, 3).Value = "") And (ActiveSheet.Cells(ind_row, 4).Value <> "") Then
ActiveSheet.Range("B" & CStr(ind_row) & ":B" & CStr(ind_row)).EntireRow.AutoFit
Application.DisplayAlerts = False
ActiveSheet.Range("B" & CStr(ind_row) & ":N" & CStr(ind_row)).Merge
Application.DisplayAlerts = True
ActiveSheet.Range("B" & CStr(ind_row) & ":N" & CStr(ind_row)).Borders(xlDiagonalDown).LineStyle = xlNone
ActiveSheet.Range("B" & CStr(ind_row) & ":N" & CStr(ind_row)).Borders(xlDiagonalUp).LineStyle = xlNone
'настройка стилей'
' ActiveSheet.Range("B" & CStr(ind_row) & ":B" & CStr(ind_row)).EntireRow.AutoFit
Else
End If
ActiveSheet.Range("B" & CStr(ind_row) & ":C" & CStr(ind_row)).EntireRow.AutoFit
ind_row = ind_row + 1
Wend
' MsgBox "Форматирование " & ActiveSheet.Name & " выполнено"
ind_row = ind_row + 1
While ActiveSheet.Cells(ind_row, 1).Value & ActiveSheet.Cells(ind_row, 3).Value & ActiveSheet.Cells(ind_row, 4).Value <> ""
Application.DisplayAlerts = False
ActiveSheet.Range("A" & CStr(ind_row) & ":N" & CStr(ind_row)).Merge
ActiveSheet.Range("A" & CStr(ind_row) & ":N" & CStr(ind_row)).HorizontalAlignment = xlLeft
Application.DisplayAlerts = True
ind_row = ind_row + 1
Wend
ActiveSheet.PageSetup.PrintArea = "$A$1:$N$" & CStr(ind_row - 1)
Next ind_sheets
Здравствуйте, Никита!
Если еще актуально, попробуйте после первой строки с While… вставить следующий код:
Добрый день,
Начал изучать VBA недавно и спотыкнулся на инструменте For Each…Next. Не могу понять как он работает
Например взял код на Microsoft Learn
Dim TestArray(10) As Integer, I As Variant
For Each I In TestArray
TestArray(I) = I
Next I
В моем понимании, по результатам выполнения программы массив должен быть наполнен: 0,1,2,3,4…
Но в итоге там нули. Вставил Debug.Print I в цикле, вижу что циклы проходят в нужном количестве, но каждый раз I=0, соответственно и массив заполнен нулями. Особенно странно что код взят с сайта Microsoft в формате copy-paste и не работает как там написано.
Другая ситуация. Немного переделанный код с Вашего сайта:
Sub Primer1()
Dim myRange, myArr(), el, ub, n, in1, in2
Set myRange = Range("B3:G7")
myArr = myRange.Value 'присваиваем массиву значения указанного диапазона
ub = UBound(myArr) 'определяем верхнюю границу первого измерения(индекса) массива
Debug.Print UBound(myArr)
Debug.Print UBound(myArr, 2)
For Each el In myArr
Debug.Print el
If el = 17 Then ' ищем например индекс 17
in1 = (n Mod ub) + 1 ' вычисляем индекс первого измерения
in2 = (n \ ub) + 1 ' вычисляем индекс второго измерения
' отображаем результаты в окне Immediate
Debug.Print "Индекс первого измерения: " & in1 'Результат: 3
Debug.Print "Индекс второго измерения: " & in2 'Результат: 5
End If
n = n + 1
Next
End Sub
Вроде все работает. Но
"Debug.Print el"
показывает что цикл проходит по значениям в массиве в беспорядочном порядке. Это конструкция так и должна работать?Понял почему нули в первом коде от MS. Значение управляющей переменной цикла I в For Each хранит текущее значение ячейки массива который «сканируется». Поэтому нули и остаются. Непонятно почему MS приводит пример данного кода для объяснения работы цикла For Each, сам код получается бессмысленным.
Остается вопрос почему «сканирование» идет в беспорядочном порядке.
Здравствуйте!
Вместо первого примера используйте следующий код, где значениям массива присвоены их индексы:
Во втором случае обход элементов массива тоже идет по порядку: если смотреть на диапазон, откуда скопированы значения, то сверху вниз — слева направо, то есть по столбцам. Не забудьте, что вначале метод Debug.Print выводит на печать UBound(myArr) и UBound(myArr, 2).
Да, еще: когда цикл нашел то, что нужно было найти, его можно остановить с помощью оператора (строки кода) —
Exit For
. В статью Определение координат элемента массива, откуда вы взяли код, я добавил выход из цикла.Обсуждение закрыто.