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

VBA Excel. Диапазон ячеек и массив (обмен значениями)

    Копирование значений из диапазона ячеек в массив и обратно с помощью VBA Excel. Простейшие примеры обмена значениями между диапазоном и массивом.


    Как известно, VBA обрабатывает информацию в массивах значительно быстрее, чем в ячейках рабочего листа Excel. Поэтому, при работе с большими объемами данных, удобнее использовать массивы, чем наблюдать во время выполнения кода за мерцанием изображения на экране или просто смотреть в неизменную картинку, если обновление экрана отключено (Application.ScreenUpdating = False). Здесь обмен значениями между массивом и диапазоном ячеек будет вполне уместен.

    Копирование значений из диапазона ячеек в массив

    Чтобы скопировать значения из диапазона ячеек в массив, необходимо объявить переменную универсального типа (As Variant) и присвоить ей значения диапазона ячеек с помощью оператора присваивания (=):

    VBA Excel автоматически преобразует объявленную переменную в двумерный массив, соответствующий размерности диапазона ячеек, в нашем случае в массив — a(1 To 3, 1 To 3), и заполняет его значениями. Нумерация измерений массивов, созданных таким образом, начинается с единицы (1).

    Можно, в этом случае, объявить сразу динамический массив, чтобы изначально указать, что эта переменная будет массивом. Так как свойством диапазона ячеек по умолчанию в VBA Excel является значение (Value), его можно в коде явно не указывать, но, при желании, можно и указать. Получится такая конструкция, аналогичная первой:

    Стоит отметить, что для копирования значений из диапазона ячеек в массив можно использовать только обычную переменную или динамический массив универсального типа (Variant). VBA Excel автоматически преобразовывает их в двумерный массив. Если объявить двумерный массив с указанной заранее размерностью, использовать его не получится, будет сгенерирована ошибка с сообщением: Can’t assign to array (Нельзя назначать массив).

    Копирование значений из массива в диапазон ячеек

    Значения в диапазон ячеек добавляются из массива с помощью оператора присваивания (=):

    Обратите внимание, что вставить значения в диапазон ячеек можно только из двумерного массива. Размерность такого массива может начинаться с нуля (0). Количество элементов в измерениях массива должно совпадать с количеством строк и столбцов в диапазоне ячеек. Если вам нужно вставить значения в одну строку или в один столбец, укажите размерность единственной строки или единственного столбца как (0) или (1 To 1), если вы хотите использовать нумерацию измерений своего массива с единицы. Например, для записи десяти значений из массива в одну строку можно объявить такой массив — massiv(9, 0), или в один столбец — massiv(0, 9).

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

    Обмен значениями между двумя диапазонами

    Обмен значениями можно осуществить в VBA Excel не только между массивом и диапазоном, но и между двумя диапазонами одинаковой размерности:

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

    Если диапазон ячеек, принимающий значения, по размеру меньше диапазона-источника, то он будет заполнен полностью:

    Если принимающий диапазон ячеек по размеру больше передающего, то часть его будет заполнена значениями диапазона-источника, а остальные ячейки — значениями #Н/Д:

    Простейшие примеры обмена значениями

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

    Пример 1

    Заполнение двумерного массива значениями и и их присвоение диапазону ячеек на рабочем листе Excel:

    В данном случае переменная массива не обязательно должна быть универсального типа (As Variant), например, если бы в нее записывались только текстовые данные, ее можно было бы объявить как строковую (As String), и все бы работало.

    Пример 2

    Объявление обычной переменной универсального типа, присвоение ей значений из диапазона ячеек «A1:C3», записанных кодом первого примера, и вставка этих значений из полученного двумерного массива в диапазон «D10:F12»:

    Естественно, указанные диапазоны ячеек расположены на активном листе.

    Пример 3

    Допустим, на рабочем листе «Лист1» в ячейках «A1:A5» записано количество какого-то товара, а в ячейках «B1:B5» — его цена. Необходимо к этой информации добавить сумму каждого товара, умножив количество на цену, и перенести данные на «Лист2».

    Массив создан сразу с размерностью 5×3 с элементами под суммы. Даже если на первом листе в ячейках «C1:C5» есть какие-то значения, в массиве они будут перезаписаны результатами вычислений.

    Копирование значений из массива в массив

    Этот пример показывает, как в VBA Excel можно скопировать значения из одного массива в другой:


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

    83 комментария для “VBA Excel. Диапазон ячеек и массив (обмен значениями)”

    1. Александр

      Вот скажем простой пример. Есть список слов разной длины. Нужно сделать массив состоящий из отдельных букв. Чем в данном случае удобнее пользоваться, массивами, коллекциями или словарями? Если потом нужно работать с таким объектом и ссылаться на его элементы.

      1. Евгений

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

    2. Джамшед

      Здравствуйте, Евгений! Помогите, пожалуйста, найти ошибку. Вот текст моего кода.

      При отладке и просмотре параметров в окне Watches, при выполнении всех условий в структурах IF…Then, цикл почему-то уходит на следующий j, при этом полностью игнорируются операторы, начиная с aa = PurchVol(j, 1) и до kk=kk+1.
      Спасибо.

      1. Евгений

        Добрый день, Джамшед!
        Если блок операторов в структуре IF…Then игнорируется, значит условие все-таки не выполняется.

        Строка ReDim Preserve DinArr(1 To kk) очищает массив, также как и строка ReDim DinArr(1 To kk, 1 To 5) As Variant. Если вы будете использовать ReDim Preserve DinArr(1 To kk, 1 To 5), то все равно массив будет очищен, так как в VBA сохраняются значения только при переопределении последнего измерения (например, 1 To 5 на 1 To 7).

        Когда разберетесь с условиями, попробуйте использовать транспонированный массив: DinArr(1 To 5, 1 To kk), который можно будет переопределять по значению переменной kk с ключевым словом Preserve.

    3. Добрый вечер! Как лучше сделать?
      Пеpенести в хвост одномеpного массива А(20) все его отрицательные элементы.

      1. Евгений

        Привет, Marina!
        Мой вариант таков:

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

    4. А можно при копировании в конечные ячейки вставлять не только данные но и формат шрифта? Помогите пожалуйста

    5. Станислав

      Евгений, добрый день! Если не составит труда окажите пож. помощь. Имеется задача по которой необходимо в рабочей книге в которой имеется до 1000000 строк (значение строк может быть переменным) найти адрес строки со значением в колонке (она всегда постоянна), которое соответствует значению из другой активной таблицы. Если такое значение имеется, то изменить увеличить значение в другой ячейке этой строки. Если не, то добавить новую строку. Т. Е. Для следующего поиска количество строк будет изменено. Эта рабочая книга и листы выражены через переменные. При использовании перебора циклом или методом поиска все заклинивает на этом объеме. Вопрос. Всегда ли в массив нужно объявлять активный лист книги. Может ли при объявлении диапазоне массива использоваться переменные? У меня возникает ошибка 9. Заранее благодарю за помощь, с уважением Станислав.

      1. Евгений

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

    6. Станислав

      Спасибо за ответ. Постараюсь объяснить суть. Я беру строку из активной книги и помещают на лист рабочей книги. При этом делаю проверку, имеется ли на листе рабочей книги строка с таким же идентификатором. Если имеется, то увеличиваю, например, сумму в имеющейся строке. Если строки с таким идентификатором нет, то добавляю после последней. Таким образом, когда начинает работать Макрос, то в начале мой диапазон, т. Е. То что я хочу присвоить массиву, есть одна пустая ячейка. Получается на листе я проверку делаю по одной колонке. И если я найду значение исковое в ней, то получу адрес строки.

    7. Есть массив А(5, 5).
      Можно ли скопировать его данные А(1, 1), А(1, 2), А(2, 1), А(2, 2) в массив В(2, 2) БЕЗ ЦИКЛОВ?
      И, разумеется, без «ручного» переписывания элементов из А в В…

      1. Евгений

        Добрый день!
        Можно скопировать через рабочий лист:

        1. Спасибо, Евгений.
          А если в массиве 2 млн «строк», и он, соответственно, не помещается на рабочий лист. Что можно предпринять тогда?

          1. Евгений

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

    8. Станислав

      Евгений, добрый день! Прошу помочь разобраться, т.к. только начал изучать массивы
      Есть рабочая книга Book.Sheets(Fil) в нее будут в колонку добавляться построчно значения ID, при очередном добавлении проверяться на наличие ID, если есть, то обновить существующую строку, если нет, то добавить новую. Учитывая большой объем строк все остальные методы зависают.

      Буду признателен за помощь

    9. Станислав

      Евгенией, избавился от ошибки.
      If arr()(Row) = ID Then ‘ в этом месте изменил на If arr()(Row, 1) = ID Then
      тогда возникает вопрос как по значению индекса или строки в массиве получить номер строки в диапазоне.

      С уважением,

      1. Евгений

        Здравствуйте, Станислав!
        Переопределять размерность массива вам не нужно (ReDim arr(1 To LastRow + 2) As Variant), так как, при присвоении ему значений диапазона, размерность будет задана автоматически.
        Первая строка массива у вас соответствует пятой строке диапазона, поэтому строка диапазона = индекс первого измерения массива + 4.

    10. Евгений, добрый день. Хотел бы узнать, как можно реализовать функцию передачи данных с листа в двумерный массив и связать их с другим листом
      Лист 1:Имеются 3 столбца (Название, Дата и Цена)
      Лист 2: Цена , Значение.
      Данные должны сохраняться в массиве и далее вызываться в другой функции.
      Кол-во данных неизвестно(динамический массив нужен)
      Спасибо

    11. Александр

      Добрый день, Евгений,
      прошу уточнить. Почему у меня при указании диапазона ячеек по форме R1C1 (например Cells(i + 1, 1).Value) появляется: «Expected variable or procedure, not module». Если указываю диапазон или адрес ячейки в формате A1, то код считает. Брал несколько Ваших примеров, но все равно не считается, если R1C1.
      Может необходимо уточнить настройки на ноуте?

      1. Евгений

        Здравствуйте, Александр!
        Разработчики пишут, что такая ошибка возникает, когда слово используется в названии модуля. Я сомневаюсь, что один из модулей у вас называется «Cells», но проверьте на всякий случай. Еще проверьте, не возвращает ли выражение Cells(i + 1, 1).Value слово или число, используемое как название одного из модулей. Посмотрите, возникает ли ошибка при запуске следующей процедуры:

    12. Александр

      Добрый день, Евгений, спасибо огромное. Начинаю изучать VBA и, действительно, один из модулей назвал Cells. Изменил на Cells_lesson и все заработало!

    13. Александр

      Добрый день, Евгений,
      подскажите, пожалуйста, почему Ubound равна 1 при выводе через MsgBox при этом в массиве 12 ячеек и в переменную массива abc4 вносятся 12 значений. LBound также равна 1.

      1. Евгений

        Александр, вы исследовали первое измерение массива, а массив у вас двумерный. Добавьте в процедуру функции LBound и UBound для второго измерения:

    14. Александр

      Евгений, спасибо, снова заработало!
      Может какой-нибудь словарь для начинающих создать? Например: — Если для массива нужен диапазон ячеек, то использовать коэффициент 2.
      В темах Вашего сайта не нашел ответ, ставил коэффициент 1 и 0, а нужно было 2.

    15. Добрый день. Подскажите пожалуйста, у меня есть диапазон, допустим Range("M3:M5003"), мне нужно при условии значения из этого диапазона изменить высоту строк другого диапазона, у меня есть макрос, но при таком количестве он долго считает, перебирая каждую ячейку по отдельyости, а вот ума не хватает как это всё занести в массив, для ускорения процесса

      1. Евгений

        Здравствуйте, Максим!
        Надеюсь, этот пример вам поможет:

    16. Леонид М.

      Здравствуйте!
      Есть диапазон (именованный или объединенный), состоящий из нескольких групп ячеек. Как передать данные из двумерного массива в этот диапазон и/ил от другого диапазона (единого) такого же размера.
      В ниже приведенном примере, когда из диапазона "K3:M11" нужно скопировать значения в массив arr и затем из массива в объединенный диапазон "C3:E5"&"C7:E10"&"C12:E13" ошибки не выводит, но в частях диапазона "C7:E10" и "C12:E13" значения вводятся уже некорректные.

      1. Евгений

        Здравствуйте, Леонид!
        В несмежный диапазон вставить данные из массива не получится. Можно сделать так:

        1. Леонид М.

          Печалька, печелюшечка… )
          Тем не менее- спасибо за ответ. А можно разъяснить или дать ссылку почему происходит некорректный перенос из цельного диапазона в несмежный? Ведь по сути это две одинаковых таблицы (в наших примерах размером 3 на 9)?

          1. Евгений

            В объектной переменной содержится ссылка на объект, а не самостоятельный объект. То есть работа через переменную Set oRange = Union(Range("C3:E5"), Range("C7:E10"), Range("C12:E13")) осуществляется с тем же несмежным диапазоном. Одна из статей на сайте разработчиков, где говорится о том, что в объектной переменной содержится ссылка, — Создание объектных переменных. Там есть предложение: «Используйте тип данных Object для создания универсальной ссылки на любой объект».

            В предыдущем ответе я предложил пример с переменными, но можно обойтись и без них:

    17. Здравствуйте, возник такой вопрос, как записывать значения из массива в таблицу через строку?

      1. Евгений

        Здравствуйте, Максим!
        В следующем примере данные копируются в массив из диапазона "A1:F10" и вставляются через одну строку, начиная с 14 строки:

    18. Добрый день, Евгений!
      Такой вопрос:
      Есть файл, из каждой строки файла надо создавать отдельный документ с конкретным диапазоном ячеек пытаюсь вытащить конкретный диапазон, но выходит ошибка. Что я делаю не так? Ругается всегда на строчку со сделанным диапазоном.

      1. Евгений

        Здравствуйте, Максим!
        Попробуйте так:

        Код для проверки:

        1. Огромное спасибо, Евгений!!!!
          Все получилось )

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

      в последней строке выдается ошибка: Application-defined or object-defined error
      Excel 2016
      В чем причина ошибки? Вроде, все, как у Вас в статье…

      1. Евгений

        Здравствуйте, Илья!
        Если в коде VBA Excel при обращении к диапазону не указан лист, то используется диапазон с активного листа активной книги. Добавьте во все строки идентификаторы (переменные) листов:

        и так далее.

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