Перейти к содержимому
Наше приложение «Дешевые авиабилеты» в AppGallery >>

VBA Excel. Цикл For Each… Next

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

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

    Синтаксис цикла For Each… Next

    В квадратных скобках указаны необязательные атрибуты цикла 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 выделите диапазон ячеек и запустите на выполнение следующую процедуру:

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

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

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

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

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

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

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

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

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

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

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

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


    Содержание рубрики VBA Excel по тематическим разделам со ссылками на все статьи.

    46 комментариев для “VBA Excel. Цикл For Each… Next”

    1. Здравствуйте!
      Я новичок в VBA, поэтому ,возможно, вопрос глупый, но не могу никак придумать процедуру для сравнения двух массивов с помощью цикла For Each… Next.
      т.е. имеются столбцы A:B — ФИО1 Дата1 и столбцы C:D — ФИО2 Дата2. Хочу сравнить и при совпадении выделить совпадающие ячейки цветом.
      Подскажите, хотя бы примерно, как это сделать.
      Спасибо

      1. Евгений

        Здравствуйте!
        Диапазоны в примере одинаковые по размеру, но могут быть любые:

        1. Спасибо большое, Евгений!
          Я немного неправильно сформулировал.
          Нужно выделить, если пары ФИО и Дата совпадают.
          т.е. Иванов 1979 и Иванов 1979 выделялись, а Иванов 1979 и Иванов 1980 нет. Так же как и Иванов 1979 и Петров 1979 не нужно выделять.
          Пока придумал только если создать дополнительные столбцы и в них прописать «=A1&B1» и по ним сравнивать.
          Можно ли как то сделать по другому?

          1. Евгений

            Можно и по-другому, попробуйте так:

            1. Сергей Васильевич

              Добрый день.
              Есть задача посложнее.
              Лист 1 . А1 инвентарный номер (10 или 12 знаков) . В1 колличество полученных деталей.
              Лист 2 . Колонка J содержит инвентарный номер (может быть несколько строк). Колонка S содержит текст внутри которого колличество полученных деталей (B1 листа 1). Колонка N содержит дату получения деталей.
              Задача надо найти по данным Листа1 совпадение А1&В1 на Листе 2 данные колонки n

    2. Здравствуйте!
      Подскажите пожалуйста, как с помощью цикла For Each…Next можно выполнить задачу:
      Есть диапазон со значениями, например («B1:С5»)
      Нужно все значения из этого диапазона последовательно вынести в столбец A (раздельно, не в одну ячейку)

      1. Евгений

        Здравствуйте, Дарья!

        1. Большое спасибо!
          У вас очень классный сайт, существенно мне помог разобраться в VBA Excel

    3. Добрый день, очень часто пользуюсь информацией с Вашего сайта, но вот тут возникла задача, с которой справиться не получается, возможно вы сможете помочь.
      У меня есть массив:

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

      1. Евгений

        Здравствуйте, Михаил!

        Найденные числа записываются в первый столбец листа «Лист1». Пустые ячейки (нули) игнорируются.

        1. Правильно ли будет отрабатываться условие "если такой цифры с противоположным знаком нет -> (то вывести в столбик такие цифры, к которым нет противоположных)" во втором цикле? Будет ложное срабатывание, когда val1=5 и val2=6, например, ведь 5<>-6.

          1. Евгений

            Привет!
            Условие

            проверяет, с какими значениями переменных закончился внутренний цикл. Если это 5 и 6, значит в массиве нет значения -5, и это не ложное, а верное срабатывание.

    4. Добрый вечер! Подскажите, пожалуйста, как исправить проблему? Дана строка символов, и нужно определить, встречаются ли в ней 5 символов «$» и 3 символа «%»? Почему-то в любом случае результат, что «Символы не встречаются». Заранее спасибо.

      1. Евгений

        Дарья, объявление переменных

        соответствует объявлению

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

    5. Здравствуйте.
      Подскажите, пожалуйста, как выполнить задачу. Есть лист1. В нем столбик А с ячейками ID(заранее известно количество строк). Нужно сравнить с ячейками ID столбика А листа2 и при совпадении записать данные из столбика К листа1 в столбик D листа2 вместе с цветом ячейки. В листе2 не известно заранее сколько строк. Я написала начало, дальше не пойму как.

      1. Евгений

        Здравствуйте, Елена!
        Как я понял из вашего кода, просмотр начинается с 3 строки. Вот два варианта решения, где вам нужно только заменить Лист11 на Worksheets("22.11-28.11") и Лист12 на второй ваш лист:

        1. Спасибо большое! Первый вариант мне как-то более понятен. Т.е. теперь, чтобы передать цвет ячейки, надо дописать перед выходом из внутреннего цикла

          Только это не работает.

          1. Евгений

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

            1. Да работает. Просто цвета, созданные условным форматированием, не переносятся

              1. Евгений

                Попробуйте

                заменить на

                Результат не гарантирован, так как он будет зависеть от формулировок правил условного форматирования.

                1. Как-то частично переносит цвет.
                  Заметила, что и на первом листе и на втором игнорируется последняя строка. Поставила n1 + 1, n2 + 1 и все работает как надо.

    6. Наталья

      Подскажите, пожалуйста,как обозначить выполнение цикла операций после проведения отбора каждого из возможных значений по одному из столбцов?
      Есть массив данных(много столбцов) с разными значениями в ячейках столбца День(от 1до 31). Нужно последовательно для каждого дня вывести массив, скопировать его (отдельные части) и перенести в другую книгу. Так для каждого дня. Т.е последовательно скопировать и вставить массивы данных в другую книгу. В общем массиве могут быть не все даты месяца.

    7. Подскажите пожалуйста есть ли способ с помощью этого цикла перекрасить объекты (Shape) имеющие в себе гиперссылки (Hyperlink) во всей книге.
      Для листа у меня вышло а для книги не могу понять как, прошу помощи так как только начал разбираться в vba.
      Код макроса.

      1. Евгений

        Здравствуйте, Денис!
        Ваш код для всей текущей книги:

    8. Владимир

      Здравствуйте. А как быть, если выбраны пользователем несмежные ячейки? Перебор не идёт (

      1. Евгений

        Здравствуйте, Владимир!
        У меня цикл For Each… Next работает и с выбранными несмежными ячейками — Selection, и с заданными как объект Range — Range("B4:B5,D7:D8,G1:G2"). Проверьте у себя еще раз на примере цикла для диапазона ячеек (test1).

    9. Здравствуйте.
      Я инженер, работаю со сметами. У нас разделы в смете, и после каждого раздела нужна подсчитать итог, разделы начинаются : " РАЗДЕЛ "НОМЕР" ****** ". У меня не получается никак. Подскажите пожалуйста.

      1. Евгений

        Здравствуйте, Андрей!
        Недостаточно информации для понимания ситуации. Объясните структуру сметы: в каком столбце находятся названия разделов, какие диапазоны надо суммировать, куда записывается результат суммирования.

        1. Таблица в столбцах A:H. Раздел находится в столбцах B:F (одна строка) мне нужно суммировать столбец H от первого раздела до следующего раздела ( все разделы по отдельности). Вверху раздела одна пустая строка, там должно вписаться результат суммы раздела в столбце H. Все разделы должны по отдельности суммироваться.

          1. Евгений

            По вашему описанию я представляю так:

            Сстрока 1 — шапка таблицы.

            Блок раздела 1:
            ячейка B2 — наименование раздела (РАЗДЕЛ 1)
            диапазон H3-H8 — диапазон суммирования
            ячейка H9 — сумма

            Блок раздела 2:
            ячейка B10 — наименование раздела (РАЗДЕЛ 2)
            диапазон H11-H20 — диапазон суммирования
            ячейка H21 — сумма

            и так далее (диапазон суммирования — величина переменная). Правильно?

    10. Да. Но разделы не "B2" а "B2:F2" то есть они объединены в одну строку (столбцы). Разделы начинаются со слова , например "Раздел 1. Кровля", то есть разделы начинается : "Раздел "номер" "****". и т.д. Мне нужно пробегаться по этим разделам и вставить итог в конце. Остальное все правильно.

      1. Евгений

        Андрей, в объединенной ячейке отображается только значение первой ячейки, поэтому обращаться к объединенной ячейке "B2:F2" будем "B2". Код будет работать при отсутствии пустых ячеек внутри суммируемых диапазонов, нули допускаются:

        1. Привет, Евгений. Ну я вписал, не работает, только n подсчитывает последнюю строку. Сумма в столбце H не вставляется, m тоже не работает.

          1. Евгений

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

    11. В строке раздела в столбце «H» пусто.
      Структура:
      В 1 столбце нумерация.
      В 2ом обоснование.
      В 3ем наименование.
      В 4ем ед.измерение.
      В 5ом норма.
      В 6ом по проекту.
      В 7ом цена
      В 8ом сумма.

      1. Евгений

        Если на пересечении строки раздела и столбца «H» пусто, тогда:

        1. Привет Евгений. Можно функцию сумм как формулу ввести, чтобы в ячейке была формула?

          1. Евгений

            Можно и формулу вставить:

            1. Спасибо Евгений, удачи тебе, очень помог!!..

    12. Здравствуйте, по работе нужно модернизировать существующий макрос, чтобы он для ячеек из диапазона столбцов от 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

      1. Евгений

        Здравствуйте, Никита!
        Если еще актуально, попробуйте после первой строки с While… вставить следующий код:

    13. Добрый день,
      Начал изучать 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" показывает что цикл проходит по значениям в массиве в беспорядочном порядке. Это конструкция так и должна работать?

      1. Понял почему нули в первом коде от MS. Значение управляющей переменной цикла I в For Each хранит текущее значение ячейки массива который «сканируется». Поэтому нули и остаются. Непонятно почему MS приводит пример данного кода для объяснения работы цикла For Each, сам код получается бессмысленным.
        Остается вопрос почему «сканирование» идет в беспорядочном порядке.

        1. Евгений

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

          Во втором случае обход элементов массива тоже идет по порядку: если смотреть на диапазон, откуда скопированы значения, то сверху вниз — слева направо, то есть по столбцам. Не забудьте, что вначале метод Debug.Print выводит на печать UBound(myArr) и UBound(myArr, 2).

    Обсуждение закрыто.