Копирование значений из диапазона ячеек в массив и обратно с помощью VBA Excel. Простейшие примеры обмена значениями между диапазоном и массивом.
Как известно, VBA обрабатывает информацию в массивах значительно быстрее, чем в ячейках рабочего листа Excel. Поэтому, при работе с большими объемами данных, удобнее использовать массивы, чем наблюдать во время выполнения кода за мерцанием изображения на экране или просто смотреть в неизменную картинку, если обновление экрана отключено (Application.ScreenUpdating = False). Здесь обмен значениями между массивом и диапазоном ячеек будет вполне уместен.
Копирование значений из диапазона ячеек в массив
Чтобы скопировать значения из диапазона ячеек в массив, необходимо объявить переменную универсального типа (As Variant) и присвоить ей значения диапазона ячеек с помощью оператора присваивания (=):
1 2 |
Dim a As Variant a = Range("A1:C3") |
VBA Excel автоматически преобразует объявленную переменную в двумерный массив, соответствующий размерности диапазона ячеек, в нашем случае в массив — a(1 To 3, 1 To 3), и заполняет его значениями. Нумерация измерений массивов, созданных таким образом, начинается с единицы (1).
Можно, в этом случае, объявить сразу динамический массив, чтобы изначально указать, что эта переменная будет массивом. Так как свойством диапазона ячеек по умолчанию в VBA Excel является значение (Value), его можно в коде явно не указывать, но, при желании, можно и указать. Получится такая конструкция, аналогичная первой:
1 2 |
Dim a() As Variant a = Range("A1:C3").Value |
Стоит отметить, что для копирования значений из диапазона ячеек в массив можно использовать только обычную переменную или динамический массив универсального типа (Variant). VBA Excel автоматически преобразовывает их в двумерный массив. Если объявить двумерный массив с указанной заранее размерностью, использовать его не получится, будет сгенерирована ошибка с сообщением: Can’t assign to array (Нельзя назначать массив).
Копирование значений из массива в диапазон ячеек
Значения в диапазон ячеек добавляются из массива с помощью оператора присваивания (=):
1 2 3 4 |
Range("A6:F15") = a 'или Range("A6:F15").Value = a 'где a - переменная двумерного массива |
Обратите внимание, что вставить значения в диапазон ячеек можно только из двумерного массива. Размерность такого массива может начинаться с нуля (0). Количество элементов в измерениях массива должно совпадать с количеством строк и столбцов в диапазоне ячеек. Если вам нужно вставить значения в одну строку или в один столбец, укажите размерность единственной строки или единственного столбца как (0) или (1 To 1), если вы хотите использовать нумерацию измерений своего массива с единицы. Например, для записи десяти значений из массива в одну строку можно объявить такой массив — massiv(9, 0), или в один столбец — massiv(0, 9).
Для вставки значений в диапазон ячеек из массива идеально подойдет массив, созданный для копирования в него значений из диапазона. В этом случае, данные с рабочего листа Excel переносятся в массив, обрабатываются и, после обработки, вставляются обратно в ту же или другую таблицу на том же или другом рабочем листе.
Обмен значениями между двумя диапазонами
Обмен значениями можно осуществить в VBA Excel не только между массивом и диапазоном, но и между двумя диапазонами одинаковой размерности:
1 |
Range("B2:D6") = Range("G7:I11").Value |
У диапазона, являющегося источником значений, обязательно должно быть указано свойство Value
.
Если диапазон ячеек, принимающий значения, по размеру меньше диапазона-источника, то он будет заполнен полностью:
1 |
Range("B2:D6") = Range("G5:L13").Value |
Если принимающий диапазон ячеек по размеру больше передающего, то часть его будет заполнена значениями диапазона-источника, а остальные ячейки — значениями #Н/Д
:
1 |
Range("B2:D6") = Range("G7:H9").Value |
Простейшие примеры обмена значениями
Эти примеры составлены так, чтобы вам не пришлось совершать лишних действий, просто скопируйте их в свой модуль любой книги Excel с поддержкой макросов и запустите по очереди на выполнение.
Пример 1
Заполнение двумерного массива значениями и и их присвоение диапазону ячеек на рабочем листе Excel:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Sub Test1() Dim a(2, 2) As Variant a(0, 0) = "телепузик" a(0, 1) = "журналист" a(0, 2) = "ящерица" a(1, 0) = "короед" a(1, 1) = "утенок" a(1, 2) = "шмель" a(2, 0) = 200 a(2, 1) = 300 a(2, 2) = 400 Range("A1:C3").Value = a End Sub |
В данном случае переменная массива не обязательно должна быть универсального типа (As Variant), например, если бы в нее записывались только текстовые данные, ее можно было бы объявить как строковую (As String), и все бы работало.
Пример 2
Объявление обычной переменной универсального типа, присвоение ей значений из диапазона ячеек «A1:C3», записанных кодом первого примера, и вставка этих значений из полученного двумерного массива в диапазон «D10:F12»:
1 2 3 4 5 |
Sub Test2() Dim a As Variant a = Range("A1:C3") Range("D10:F12") = a End Sub |
Естественно, указанные диапазоны ячеек расположены на активном листе.
Пример 3
Допустим, на рабочем листе «Лист1» в ячейках «A1:A5» записано количество какого-то товара, а в ячейках «B1:B5» — его цена. Необходимо к этой информации добавить сумму каждого товара, умножив количество на цену, и перенести данные на «Лист2».
1 2 3 4 5 6 7 8 9 |
Sub Test3() Dim a As Variant, i As Long a = Лист1.Range("A1:C5") For i = 1 To 5 a(i, 3) = a(i, 1) _ * a(i, 2) Next Лист2.Range("A1:C5") = a End Sub |
Массив создан сразу с размерностью 5×3 с элементами под суммы. Даже если на первом листе в ячейках «C1:C5» есть какие-то значения, в массиве они будут перезаписаны результатами вычислений.
Копирование значений из массива в массив
Этот пример показывает, как в VBA Excel можно скопировать значения из одного массива в другой:
1 2 3 4 5 6 |
Sub Test4() Dim arr1, arr2 arr1 = Range("G7:I11") arr2 = arr1 Range("B2:D6") = arr2 End Sub |
«Еще стоит отметить, что объявить динамический массив можно, а вот использовать обычный двумерный массив с указанной заранее размерностью не получится.»
А почему? Не ясно где и как именно применяется двумерный массив и, соответственно, почему не получится его применить
Артем, двумерные массивы в VBA Excel используются без ограничений, как и массивы с другим количеством измерений. Тесты показали, что значения ячеек невозможно присвоить заранее объявленному двумерному массиву (естественно с размерностью, соответствующей диапазону ячеек):
Выполнение кода сгенерирует ошибку, а если убрать размерность при объявлении переменной, все заработает корректно. Процитированную вами строку я изменил, чтобы она точнее передавала смысл.
Честно говоря выше так и не понял фразу даже после корректировки, а вот в комментарии вы все описали ясно и понятно. Спасибо!
Евгений, можете показать пример, когда данные с рабочего листа Excel переносятся в массив, обрабатываются и, после обработки, вставляются на другой лист или в другую книгу
Нурислам, в качестве ответа я добавил в статью «Пример 3».
Евгений.
Дано: массив (1 to 5, 1 to 10, 1 to 3)
по порядку:
1-5 периоды (пусть 1, 2, 3, 4, 5)
1-10 — Наименование товара (10 вариантов)
1-3 — цена в разных магазинах (цена1, цена2, цена3).
Пусть массив заполнен полностью.
Вопрос:
Как быстро вывести на экран (лист) данные массива относящиеся к периоду 2 (например)?
Спасибо!
Василий,
для быстрого выведения информации на рабочий лист Excel используйте еще один массив, двумерный. Заполняйте его циклом, который с элементами массива работает намного быстрее, чем с ячейками.
Добрый день, Евгений!
Подскажите, пожалуйста, если необходимо вставить значения таблицы — перечень клиентов в соответствующие поля динамической таблицы. Как будет выглядеть?
Здравствуйте, Катерина!
Если динамическая таблица расположена в левом верхнем углу рабочего листа, используйте при вставке данных обычную адресацию рабочего листа вида
Range(Cells(1, 1), Cells(2, 2))
.Если динамическая таблица расположена не в левом верхнем углу рабочего листа, использование адресации умной таблицы вида
Range("Таблица1").Range(Cells(1, 1), Cells(2, 2))
будет оправдано тем, что не придется изменять код при удалении строк выше таблицы и столбцов левее.Евгений, спасибо за статью, очень глупый вопрос можно. А как выгрузить только один элемент массива в ячейку?
Здравствуйте, Татьяна!
Обратиться к отдельному элементу массива, чтобы скопировать его значение в ячейку, можно по его индексам:
Евгений, спасибо за быстрый ответ. Но я заметила, что это будет работать только при двумерном массиве. А если массив одномерный (взят диапазон столбца), то не получается у меня
Если массив одномерный, заполненный циклом по одному элементу, тогда значения копируются так:
Но если массив заполнен одной строкой, путем присвоения ему значений диапазона (пусть даже части одного столбца), в этом случае массив автоматически преобразуется в двумерный с индексацией измерений, начиная с единицы.
Евгений, спасибо большое, очень хорошее и полное объяснение! Только остался еще вопрос — чтобы рабоать с динамическим массивом после копирования из диапазона ячеек, его надо переопределить с preserve?
Привет, Ольга!
1) Вы можете переопределить массив с оператором Preserve, только учитывайте, что таким способом можно переопределить только последнее измерение массива. Если условно сопоставить двумерный массив с диапазоном ячеек, то расширение возможно только путем «добавления столбцов», количеству которых соответствует значение второго измерения.
2) Если вам нужно добавить «строки», вы можете присвоить массиву значения диапазона на нужное количество строк больше, чтобы использовать их для промежуточных расчетов. Например, вместо диапазона A1:C3 с нужными значениями можно присвоить массиву значения диапазона A1:C4 и элементы ИмяМассива(4, 1), ИмяМассива(4, 2), ИмяМассива(4, 3) использовать для промежуточных расчетов.
3) Для промежуточных расчетов можно объявить отдельный массив.
Евгений, благодарю от души! Удовольствие Вас читать, настолько все полно и понятно описано)
Спасибо, Ольга, за добрые слова и столь высокую оценку!
а как в строку через запятую это написать
Привет, ASD!
В этом случае не обойтись без цикла:
Добрый день.
Есть массив A(1,3,5)
Как в вывести в ячейки на лист1 не только элементы этого массива, а еще и индексы.
То есть должно получиться так:
Строка с индексами: 1 2 3
Строка с элементами:1 3 5
Добрый день, Руслан!
Вывести индексы в ячейки можно с помощью циклов For…Next:
Здравствуйте!
Пытаюсь приделать пользовательский формат данных к массиву
всё работает.
Но если я использую динамический массив
то при этом происходит ошибка (не удаётся найти элемент в массиве?)
почему это происходит?
Спасибо!
Любому динамическому массиву перед его заполнением по отдельным элементам необходимо задать размерность с помощью ключевого слова ReDim.
Для заданной матрицы из 4 столбцов и 10 строк вычислить количество элементов, у которых значение больше площади заданного треугольника (а, b заданы). Расположить матрицу, начиная с ячейки C1. Диапазон элементов [-13;15]. Как решить такую задачу?
Привет, Анна!
Решение может быть таким:
Здравствуйте! Как можно перезаписать массив, без выбранного столбца или строки?
Забыла указать, что перезапись идёт в другой массив
Здравствуйте, Анастасия!
Передать значения из одного массива в другой без использования диапазона ячеек можно с помощью циклов For… Next.
Подскажите, пожалуйста, как можно сформированный масив сохранить в txt файл а потом выгрузить?
Привет, Игорь!
Ответ не простой, у меня целая статья получилась.
Добрый день,
а если у меня в двумерном массиве в каждой строке или каждом столбце должно быть разное количество элементов, что лучше использовать массивы, коллекции или dictionary?
Добрый день! Лучше использовать или один массив на всю таблицу, или по отдельному массиву на каждую строку или столбец.
А если заранее не известно число строк, как создавать имена таких массивов с индексами, чтобы потом можно было сослаться на один из массивов и его элемент?
Range(«A1») – верхняя левая ячейка таблицы.
Но это я должен выгружать значения в таблицу. А нет ли какой-то структуры, чтобы сразу можно было сделать массив с разным количеством элементов в каждой строке?
В Dictionary нельзя каждому ключу задать несколько Item?
Мне такая структура не известна, но можно объявить массив с наибольшим количеством необходимых строк и столбцов, лишние останутся пустыми.
Dictionary допускает только уникальные ключи, но вы можете использовать такую индексацию: для первой строки – 1_1, 1_2 …, для второй – 2_1, 2_2 … и т.д.
Здравствуйте, Евгений, у меня к вам небольшой вопрос: у меня есть двумерный массив четных и нечетных чисел, как из этого массива вычленить четные числа и нечетные числа и добавить их в пустой массив для четных чисел и нечетных чисел соответственно?
Sub mas1()
Dim a() As Integer
Dim chet() As Integer
Dim nechet() As Integer
Dim m As Integer
Dim n As Integer
Dim i As Integer
Dim j As Integer
Dim l As Integer
Dim b As Integer
Dim sumchet As Integer
Dim countchet As Integer
Dim sumnechet As Integer
Dim countnechet As Integer
Worksheets("Лист1").Select
Cells.Clear
count = 0
m = InputBox("Введите M")
n = InputBox("Введите N")
ReDim a(1 To m, 1 To n)
ReDim chet(1 To j, 1 To i)
ReDim nechet(1 To j, 1 To i)
For j = 1 To m
For i = 1 To n
a(j, i) = Int(Rnd() * 100) - 50
Cells(j + 5, i + 5) = a(j, i)
Next i
Next j
If a(j, i) Mod 2 = 0 Then
Cells(i, 1).Value = chet(j, i)
End If
If a(j, i) Mod 2 0 Then
Cells(i, 4).Value = nechet(j, i)
End If
For l = 1 To n
For b = 1 To m
If a(b, l) Mod 2 = 0 Then
countchet = countchet + 1
sumchet = sumchet + a(b, l)
Cells(31, 1) = ("Количество четных чисел: ") & (countchet)
Cells(32, 1) = ("Сумма четных чисел массива: ") & (sumchet)
End If
Next b
Next l
For l = 1 To n
For b = 1 To m
If a(b, l) Mod 2 0 Then
countnechet = countnechet + 1
sumnechet = sumnechet + a(b, l)
Cells(31, 5) = ("Количество нечетных чисел: ") & (countnechet)
Cells(32, 5) = ("Сумма нечетных чисел массива: ") & (sumnechet)
End If
Next b
Next l
If sumchet > sumnechet Then
Cells(36, 3).Value = "Сумма четных чисел больше."
ElseIf sumchet countnechet Then
Cells(34, 3).Value = "Количество четных чисел больше."
ElseIf countchet < countnechet Then
Cells(34, 3).Value = "Количество нечетных чисел больше."
Else
Cells(34, 3).Value = "Количество четных и нечетных чисел равна."
End If
End Sub
Обсуждение закрыто.