Is it possible to either:
-
Declare an array as a constant
OR
-
Use a workaround to declare an array that is protected from adding, deleting or changing elements, and therefore functionally constant during the life of a macro?
Of course I could do this:
Const myConstant1 As Integer = 2
Const myConstant2 As Integer = 13
Const myConstant3 As Integer = 17
Const myConstant4 ...and so on
…but it loses the elegance of working with arrays. I could also load the constants into an array, and reload them each time I use them, but any failure to reload the array with those constant values before use could expose the code to a «constant» value that has changed.
Any workable answer is welcome but the ideal answer is one that can be setup once and not require any changes/maintenance when other code is modified.
asked Dec 8, 2016 at 18:15
You could use a function to return the array and use the function as an array.
Function ContantArray()
ContantArray = Array(2, 13, 17)
End Function
answered Dec 8, 2016 at 18:32
11
How about making it a function? Such as:
Public Function myConstant(ByVal idx As Integer) As Integer
myConstant = Array(2, 13, 17, 23)(idx - 1)
End Function
Sub Test()
Debug.Print myConstant(1)
Debug.Print myConstant(2)
Debug.Print myConstant(3)
Debug.Print myConstant(4)
End Sub
Nobody can change it, resize it, or edit its content… Moreover, you can define your constants on just one line!
answered Dec 8, 2016 at 18:22
A.S.HA.S.H
29k5 gold badges22 silver badges49 bronze badges
I declared a String
constant of "1,2,3,4,5"
and then used Split
to create a new array, like so:
Public Const myArray = "1,2,3,4,5"
Public Sub createArray()
Dim i As Integer
A = Split(myArray, ",")
For i = LBound(A) To UBound(A)
Debug.Print A(i)
Next i
End Sub
When I tried to use ReDim
or ReDim Preserve
on A
it did not let me. The downfall of this method is that you can still edit the values of the array, even if you can’t change the size.
answered Dec 8, 2016 at 18:21
SoulfireSoulfire
4,21821 silver badges32 bronze badges
2
If the specific VBA environment is Excel-VBA then a nice syntax is available from the Excel Application’s Evaluate method which can be shortened to just square brackets.
Look at this
Sub XlSerialization1()
Dim v
v = [{1,2;"foo",4.5}]
Debug.Assert v(1, 1) = 1
Debug.Assert v(1, 2) = 2
Debug.Assert v(2, 1) = "foo"
Debug.Assert v(2, 2) = 4.5
'* write all cells in one line
Sheet1.Cells(1, 1).Resize(2, 2).Value2 = v
End Sub
answered Apr 17, 2018 at 22:43
S MeadenS Meaden
8,0313 gold badges31 silver badges65 bronze badges
2
If you don’t need a new instance each time you can use a Static
local variable to avoid multiple objects creation and initialization:
Private Function MyConstants()
Static constants As Variant
If IsEmpty(constants) Then
constants = Array(2, 13, 17)
End If
MyConstants = constants
End Function
answered Jan 30, 2019 at 18:52
PragmateekPragmateek
13.1k9 gold badges73 silver badges108 bronze badges
Can an array be declared as a constant? No.
Workarounds — Simplest one I can think of is to define a constant with delim and then use Split
function to create an array.
Const myConstant = "2,13,17"
Sub Test()
i = Split(myConstant, ",")
For j = LBound(i) To UBound(i)
Debug.Print i(j)
Next
End Sub
answered Dec 8, 2016 at 18:20
Pankaj JajuPankaj Jaju
5,3212 gold badges25 silver badges41 bronze badges
Is this too simplistic?
PUBLIC CONST MyArray = "1,2,3,4"
then later in a module:
Dim Arr as Variant
SET Arr = split(MyArray,",")
answered Mar 3, 2019 at 21:29
1
I know this is an old question, but these archives are often scanned for many years after being posted, so I don’t see a problem with adding things long after the origin date.
How about creating a class, with a read-only property returning the ‘array’ value? You can specify a parameter using the same syntax as an array index, and defining only a GET property effectively makes it read-only. Define the constant values inside the class and it will work just like a constant array, even though the actual construction is different.
answered Mar 21, 2021 at 23:17
Using above information, I came to following working solution for comparing short text information of a month, independent from Excel using German language:
Const MONATE = «,Jän,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez»
.. and later in the code:
If StringToCompare = Split(MONATE, ",")(Month(dt)) Then
NOTE: as the Split-Array starts with index 0 I added the comma in the beginning.
answered Oct 4, 2021 at 18:42
CSohuCSohu
111 bronze badge
Don’t know when this changed, but in Excel 365, this works (or, at least, does not generate a compiler error):
Const table1Defs As Variant = Array("value 1", 42, Range("A1:D20"))
z32a7ul
3,2423 gold badges20 silver badges42 bronze badges
answered Sep 4, 2019 at 16:22
2
Содержание
- Vba excel массив как константа
- Может ли массив быть объявлен константой?
- 6 ответов
- Все про массивы в VBA
- Краткое руководство по массивам VBA
- Введение
- Быстрые заметки
- Что такое массивы и зачем они нужны?
- Типы массивов VBA
- Объявление массива
- Присвоение значений массиву
- Использование функций Array и Split
- Использование циклов с массивами
- Использование Erase
- ReDim с Preserve
- Сортировка массива
- Передача массива в Sub или функцию
- Возвращение массива из функции
- Двумерные массивы
- Чтение из диапазона ячеек в массив
- Как заставить ваши макросы работать на суперскорости
- Заключение
Vba excel массив как константа
Здесь обсуждаются вопросы по языку Visual Basic 1-6 (а так же по схожим языкам, как, например, PowerBASIC).
Вопросы по Visual Basic .NET (это который входит в состав Visual Studio 2002/2003/2005/2008+, для тех, кто не в курсе) обсуждаются в разделе .NET.
Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что Вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются. Студенты, вам сюда: ПОМОЩЬ СТУДЕНТАМ !
4. Используйте теги [ code=vba ] . текст программы. [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Формулируйте свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной (и более) давности, без веских на то причин.
Полезные ссылки:
FAQ Сайта FAQ Раздела Кладовка Наши Исходники API-Guide Поиск по Разделу MSDN Library Online Google
Ваше мнение о модераторах: SCINER, B.V.
Источник
Может ли массив быть объявлен константой?
возможно ли либо:
объявить массив как константа
использовать обходной путь для объявления массива, защищенного от добавления, удаления или изменения элементов и, следовательно, функционально постоянного в течение жизни макроса?
конечно, я мог бы это сделать:
. но он теряет элегантность работы с массивами. Я также могу загрузить константы в массив и перезагружать их каждый раз, когда я их использую, но любая неспособность перезагрузить массив с этими постоянными значениями перед использованием может подвергнуть код «постоянному» значению, которое изменилось.
любой работоспособный ответ приветствуется, но идеальным ответом является тот, который может быть настроен один раз и не требует каких-либо изменений/обслуживания при изменении другого кода.
6 ответов
вы можете использовать функцию для возврата массива и использовать функцию в качестве массива.
Как насчет того, чтобы сделать его функцией? Например:
никто не может изменить его, изменить его размер или изменить его содержимое. Кроме того, вы можете определить свои константы на одной строке!
заявил String постоянная «1,2,3,4,5» и затем использовать Split создать новый массив, например так:
когда я пытался использовать ReDim или ReDim Preserve on A он мне не позволил. Недостатком этого метода является то, что вы все равно можете редактировать значения массива, даже если вы не можете изменить размер.
можно ли объявить массив константой? Нет.
обходные пути-самый простой, который я могу придумать, это определить константу с delim, а затем использовать Split функция для создания массива.
нет — массивы не могут быть объявлены как константы, но вы можете использовать обходной путь.
вы можете создать функцию, которая возвращает массив, который вы хотите
Если конкретной средой VBA является Excel-VBA, то хороший синтаксис доступен из метода оценки приложения Excel, который можно сократить до квадратных скобок.
Источник
Все про массивы в VBA
Список настолько же силен, как и его самое слабое звено
В таблице ниже краткая справка по использованию массивов в VBA. В статье постарался замахнуться на звание самого подробного руководства, которое вы найдете о массивах VBA.
Краткое руководство по массивам VBA
Задача | Статический массив |
Динамический массив |
Объявление | Dim arr(0 To 5) As Long |
Dim arr() As Long Dim arr As Variant |
Установить размер | Dim arr(0 To 5) As Long |
ReDim arr(0 To 5)As Variant |
Увеличить размер (сохранить существующие данные) |
Только динамический |
ReDim Preserve arr(0 To 6) |
Установить значения |
arr(1) = 22 | arr(1) = 22 |
Получить значения | total = arr(1) | total = arr(1) |
Первая позиция | LBound(arr) | LBound(arr) |
Последняя позиция | Ubound(arr) | Ubound(arr) |
Читать все записи (1D) | For i = LBound(arr) To UBound(arr) Next i Or For i = LBound(arr,1) To UBound(arr,1) Next i |
For i = LBound(arr) To UBound(arr) Next i Or For i = LBound(arr,1) To UBound(arr,1) Next i |
Читать все записи (2D) | For i = LBound(arr,1) To UBound(arr,1) For j = LBound(arr,2) To UBound(arr,2) Next j Next i |
For i = LBound(arr,1) To UBound(arr,1) For j = LBound(arr,2) To UBound(arr,2) Next j Next i |
Читать все записи | Dim item As Variant For Each item In arr Next item |
Dim item As Variant For Each item In arr Next item |
Перейти на Sub | Sub MySub(ByRef arr() As String) | Sub MySub(ByRef arr() As String) |
Возврат из функции | Function GetArray() As Long() Dim arr(0 To 5) As Long GetArray = arr End Function |
Function GetArray() As Long() Dim arr() As Long GetArray = arr End Function |
Получить от функции |
Только динамический |
Dim arr() As Long Arr = GetArray() |
Стереть массив | Erase arr *Сбрасывает все значения по умолчанию |
Erase arr *Удаляет массив |
Строка в массив | Только динамический |
Dim arr As Variant arr = Split(«James:Earl:Jones»,»:») |
Массив в строку | Dim sName As String sName = Join(arr, «:») |
Dim sName As String sName = Join(arr, «:») |
Заполните значениями |
Только динамический |
Dim arr As Variant arr = Array(«John», «Hazel», «Fred») |
Диапазон в массив | Только динамический |
Dim arr As Variant arr = Range(«A1:D2») |
Массив в диапазон | Так же, как в динамическом |
Dim arr As Variant Range(«A5:D6») = arr |
Введение
В этой статье подробно рассматриваются массивы на языке программирования Excel VBA. Она охватывает важные моменты, такие как:
- Зачем вам массивы
- Когда вы должны их использовать
- Два типа массивов
- Использование более одного измерения
- Объявление массивов
- Добавление значений
- Просмотр всех предметов
- Супер эффективный способ чтения Range в массив
В первом разделе мы рассмотрим, что такое массивы и зачем они нужны. Вы можете не понимать часть кода в первом разделе. Это нормально. Я буду разбивать на простые термины в следующих разделах статьи.
Быстрые заметки
Иногда коллекции лучше, чем массивы. Вы можете прочитать о коллекциях здесь.
Массивы и циклы идут рука об руку. Наиболее распространенными циклами, которые вы используете с массивами, являются циклы For i и For Each.
Что такое массивы и зачем они нужны?
Массив VBA — это тип переменной. Используется для хранения списков данных одного типа. Примером может быть сохранение списка стран или списка итогов за неделю.
В VBA обычная переменная может хранить только одно значение за раз.
В следующем примере показана переменная, используемая для хранения оценок ученика.
Если мы хотим сохранить оценки другого ученика, нам нужно создать вторую переменную.
В следующем примере у нас есть оценки пяти студентов
Мы собираемся прочитать эти отметки и записать их в Immediate Window.
Примечание. Функция Debug.Print записывает значения в Immediate Window. Для просмотра этого окна выберите View-> Immediate Window из меню (сочетание клавиш Ctrl + G).
Как видите в следующем примере, мы пишем один и тот же код пять раз — по одному для каждого учащегося.
Ниже приведен вывод из примера
Проблема с использованием одной переменной для каждого учащегося заключается в том, что вам необходимо добавить код для каждого учащегося. Поэтому, если в приведенном выше примере у вас будет тысяча студентов, вам понадобится три тысячи строк кода!
К счастью, у нас есть массивы, чтобы сделать нашу жизнь проще. Массивы позволяют нам хранить список элементов данных в одной структуре.
Следующий код показывает приведенный выше пример с использованием массива.
Преимущество этого кода в том, что он будет работать для любого количества студентов. Если нам нужно изменить этот код для работы с 1000 студентами, нам нужно всего лишь изменить (от 1 до 5) на (от 1 до 1000) в декларации. В предыдущем примере нам нужно было добавить примерно пять тысяч строк кода.
Давайте проведем быстрое сравнение переменных и массивов. Сначала мы сравним процесс объявления.
Далее мы сравниваем присвоение значения
Наконец, мы смотрим на запись значений
Как видите, использование переменных и массивов очень похоже.
Важным является тот факт, что массивы используют индекс (также называемый нижним индексом) для доступа к каждому элементу. Это означает, что мы можем легко получить доступ ко всем элементам в массиве, используя цикл For.
Теперь, когда у вас есть представление о том, почему массивы полезны, давайте пройдемся по ним шаг за шагом.
Типы массивов VBA
В VBA есть два типа массивов:
- Статический — массив фиксированного размера.
- Динамический — массив, в котором размер задается во время выполнения
Разница между этими массивами в основном в том, как они создаются. Доступ к значениям в обоих типах массивов абсолютно одинаков. В следующих разделах мы рассмотрим оба типа.
Объявление массива
Статический массив объявляется следующим образом
Как видите, размер указывается при объявлении статического массива. Проблема в том, что вы никогда не можете быть заранее уверены, какой размер вам нужен. Каждый раз, когда вы запускаете макрос, у вас могут быть разные требования к размеру.
Если вы не используете все расположения массива, ресурсы тратятся впустую. Если вам нужно больше места, вы можете использовать ReDim, но это по сути создает новый статический массив.
Динамический массив не имеет таких проблем. Вы не указываете размер, когда объявляете. Поэтому вы можете увеличиваться и уменьшаться по мере необходимости.
Динамический массив не выделяется, пока вы не используете оператор ReDim. Преимущество в том, что вы можете подождать, пока не узнаете количество элементов, прежде чем устанавливать размер массива. Со статическим массивом вы должны указать размер заранее.
Присвоение значений массиву
Чтобы присвоить значения массиву, вы используете номер местоположения (пересечении строки и столбца). Вы присваиваете значение для обоих типов массивов одинаково.
Номер места называется индексом. Последняя строка в примере выдаст ошибку «Индекс вне диапазона», так как в примере массива нет местоположения 4.
Использование функций Array и Split
Вы можете использовать функцию Array для заполнения массива списком элементов. Вы должны объявить массив как тип Variant. Следующий код показывает, как использовать эту функцию.
Массив, созданный функцией Array, начнется с нулевого индекса, если вы не используете Option Base 1 в верхней части вашего модуля. Затем он начнется с первого индекса. В программировании, как правило, считается плохой практикой иметь ваши реальные данные в коде. Однако иногда это полезно, когда вам нужно быстро протестировать некоторый код. Функция Split используется для разделения строки на массив на основе разделителя. Разделитель — это символ, такой как запятая или пробел, который разделяет элементы.
Следующий код разделит строку на массив из трех элементов.
Функция Split обычно используется, когда вы читаете из cvs или txt-файла, разделенного запятыми, или из другого источника, который предоставляет список элементов, разделенных одним и тем же символом.
Использование циклов с массивами
Использование цикла For обеспечивает быстрый доступ ко всем элементам массива. Вот где сила использования массивов становится очевидной. Мы можем читать массивы с десятью значениями или десятью тысячами значений, используя те же несколько строк кода. В VBA есть две функции: LBound и UBound. Эти функции возвращают самый маленький и самый большой индекс в массиве. В массиве arrMarks (от 0 до 3) LBound вернет 0, а UBound вернет 3.
В следующем примере случайные числа присваиваются массиву с помощью цикла. Затем он печатает эти числа, используя второй цикл.
Функции LBound и UBound очень полезны. Их использование означает, что наши циклы будут работать правильно с любым размером массива. Реальное преимущество заключается в том, что если размер массива изменяется, нам не нужно менять код для печати значений. Цикл будет работать для массива любого размера, пока вы используете эти функции.
Использование цикла For Each
Вы можете использовать цикл For Each с массивами. Важно помнить, что он доступен только для чтения. Это означает, что вы не можете изменить значение в массиве.
В следующем коде значение метки изменяется, но оно не меняет значение в массиве.
Цикл For Each отлично подходит для чтения массива. Как видите, лучше писать специально для двумерного массива.
Использование Erase
Функция Erase может использоваться для массивов, но она работает по-разному в зависимости от типа массива.
Для статического массива функция Erase сбрасывает все значения по умолчанию. Если массив состоит из целых чисел, то все значения устанавливаются в ноль. Если массив состоит из строк, то все строки устанавливаются в «» и так далее.
Для динамического массива функция удаления стирает память. То есть она удаляет массив. Если вы хотите использовать его снова, вы должны использовать ReDim для выделения памяти.
Давайте рассмотрим пример статического массива. Этот пример аналогичен примеру ArrayLoops в последнем разделе с одним отличием — мы используем Erase после установки значений. Когда значение будет распечатано, все они будут равны нулю.
Теперь мы попробуем тот же пример с динамикой. После того, как мы используем Erase, все места в массиве были удалены. Нам нужно использовать ReDim, если мы хотим использовать массив снова.
Если мы попытаемся получить доступ к членам этого массива, мы получим ошибку «Индекс вне диапазона».
ReDim с Preserve
Если мы используем ReDim для существующего массива, то массив и его содержимое будут удалены.
В следующем примере второй оператор ReDim создаст совершенно новый массив. Исходный массив и его содержимое будут удалены.
Если мы хотим расширить размер массива без потери содержимого, мы можем использовать ключевое слово Preserve.
Когда мы используем Redim Preserve, новый массив должен начинаться с того же начального размера, например мы не можем сохранить от (0 до 2) до (от 1 до 3) или до (от 2 до 10), поскольку они являются различными начальными размерами.
В следующем коде мы создаем массив с использованием ReDim, а затем заполняем массив типами фруктов.
Затем мы используем Preserve для увеличения размера массива, чтобы не потерять оригинальное содержимое.
Из приведенных ниже снимков экрана видно, что исходное содержимое массива было «сохранено».
Предостережение: в большинстве случаев вам не нужно изменять размер массива, как мы делали в этом разделе. Если вы изменяете размер массива несколько раз, то вам захочется рассмотреть возможность использования коллекции.
Использование Preserve с 2-мерными массивами
Preserve работает только с верхней границей массива.
Например, если у вас есть двумерный массив, вы можете сохранить только второе измерение, как показано в следующем примере:
Если мы попытаемся использовать Preserve на нижней границе, мы получим ошибку «Индекс вне диапазона».
В следующем коде мы используем Preserve для первого измерения. Запуск этого кода приведет к ошибке «Индекс вне диапазона»:
Когда мы читаем из диапазона в массив, он автоматически создает двумерный массив, даже если у нас есть только один столбец.
Применяются те же правила сохранения. Мы можем использовать Preserve только на верхней границе, как показано в следующем примере:
Сортировка массива
В VBA нет функции для сортировки массива. Мы можем отсортировать ячейки листа, но это медленно, если данных много.
Функция быстрой сортировки ниже может использоваться для сортировки массива.
Вы можете использовать эту функцию так:
Передача массива в Sub или функцию
Иногда вам нужно будет передать массив в процедуру. Вы объявляете параметр, используя круглые скобки, аналогично тому, как вы объявляете динамический массив.
Переход к процедуре с использованием ByRef означает, что вы передаете ссылку на массив. Таким образом, если вы измените массив в процедуре, он будет изменен, когда вы вернетесь.
Примечание. Когда вы используете массив в качестве параметра, он не может использовать ByVal, он должен использовать ByRef. Вы можете передать массив с помощью ByVal, сделав параметр вариантом.
Возвращение массива из функции
Важно помнить следующее. Если вы хотите изменить существующий массив в процедуре, вы должны передать его как параметр, используя ByRef (см. Последний раздел). Вам не нужно возвращать массив из процедуры.
Основная причина возврата массива — это когда вы используете процедуру для создания нового. В этом случае вы присваиваете возвращаемый массив массиву в вызывающей программе. Этот массив не может быть уже выделен. Другими словами, вы должны использовать динамический массив, который не был выделен.
Следующие примеры показывают это:
Двумерные массивы
Массивы, на которые мы смотрели до сих пор, были одномерными. Это означает, что массивы представляют собой один список элементов.
Двумерный массив — это список списков. Если вы думаете об одной строке электронной таблицы как об одном измерении, то более одного столбца является двухмерным. На самом деле электронная таблица является эквивалентом двумерного массива. Он имеет два измерения — строки и столбцы.
Следует отметить одну маленькую вещь: Excel обрабатывает одномерный массив как строку, если вы записываете его в электронную таблицу. Другими словами, массив arr (от 1 до 5) эквивалентен arr (от 1 до 1, от 1 до 5) при записи значений в электронную таблицу.
На следующем рисунке показаны две группы данных. Первый — это одномерный массив, а второй — двухмерный.
Чтобы получить доступ к элементу в первом наборе данных (одномерном), все, что вам нужно сделать, это дать строку, например. 1,2, 3 или 4.
Для второго набора данных (двумерного) вам нужно указать строку И столбец. Таким образом, вы можете думать, что 1-мерное — это несколько столбцов, а одна строка и двухмерное — это несколько строк и несколько столбцов.
Примечание. В массиве может быть более двух измерений. Это редко требуется. Если вы решаете проблему с помощью 3+-мерного массива, то, вероятно, есть лучший способ сделать это.
Вы объявляете двумерный массив следующим образом:
В следующем примере создается случайное значение для каждого элемента в массиве и печатается значение в Immediate Window.
Видите, что мы используем второй цикл For внутри первого цикла, чтобы получить доступ ко всем элементам.
Результат примера выглядит следующим образом:
Этот макрос работает следующим образом:
- Входит в цикл i
- i установлен на 0
- цикл Enters j
- j установлен на 0
- j установлен в 1
- j установлен на 2
- Выход из цикла j
- i установлен в 1
- j установлен на 0
- j установлен в 1
- j установлен на 2
- И так до тех пор, пока i = 3 и j = 2
Заметьте, что LBound и UBound имеют второй аргумент 2. Это указывает, что это верхняя или нижняя граница второго измерения. Это начальное и конечное местоположение для j. Значение по умолчанию 1, поэтому нам не нужно указывать его для цикла i.
Использование цикла For Each
Использование For Each лучше использовать при чтении из массива.
Давайте возьмем код сверху, который выписывает двумерный массив.
Теперь давайте перепишем его, используя цикл For Each. Как видите, нам нужен только один цикл, и поэтому гораздо проще написать:
Использование цикла For Each дает нам массив только в одном порядке — от LBound до UBound. В большинстве случаев это все, что вам нужно.
Чтение из диапазона ячеек в массив
Если вы читали мою статью о ячейках и диапазонах, то вы знаете, что VBA имеет чрезвычайно эффективный способ чтения из диапазона ячеек в массив и наоборот.
Динамический массив, созданный в этом примере, будет двухмерным массивом. Как видите, мы можем прочитать весь диапазон ячеек в массив всего за одну строку.
В следующем примере будут считаны примеры данных студента ниже из C3: E6 Лист1 и распечатаны в Immediate Window.
Как видите, первое измерение (доступное через i) массива — это строка, а второе — столбец. Чтобы продемонстрировать это, взглянем на значение 44 в Е4 данных образца. Это значение находится в строке 2 столбца 3 наших данных. Вы можете видеть, что 44 хранится в массиве в StudentMarks (2,3).
Как заставить ваши макросы работать на суперскорости
Если ваши макросы работают очень медленно, этот раздел будет очень полезным. Особенно, если вы имеете дело с большими объемами данных. В VBA это держится в секрете.
Обновление значений в массивах происходит экспоненциально быстрее, чем обновление значений в ячейках.
В последнем разделе вы увидели, как мы можем легко читать из группы ячеек в массив и наоборот. Если мы обновляем много значений, то мы можем сделать следующее
- Скопируйте данные из ячеек в массив.
- Измените данные в массиве.
- Скопируйте обновленные данные из массива обратно в ячейки.
Например, следующий код будет намного быстрее, чем код ниже:
Назначение из одного набора ячеек в другой также намного быстрее, чем с помощью копирования и вставки.
Заключение
Ниже приводится краткое изложение основных моментов этой статьи.
- Массивы — это эффективный способ хранения списка элементов одного типа.
- Вы можете получить доступ к элементу массива напрямую, используя номер местоположения, который известен как индекс.
- Распространенная ошибка «Индекс вне диапазона» вызвана доступом к несуществующему местоположению.
- Существует два типа массивов: статический и динамический.
- Статический используется, когда размер массива всегда одинаков.
- Динамические массивы позволяют вам определять размер массива во время выполнения.
- LBound и UBound обеспечивают безопасный способ поиска самых маленьких и самых больших подписок массива.
- Основной массив является одномерным. Есть еще многомерные массивы.
- Чтобы только передать массив в процедуру, используйте ByRef. Вы делаете это так: ByRef arr() as long.
- Вы можете вернуть массив из функции, но массив, которому он назначен, не должен быть выделен в данный момент.
- Рабочий лист с его строками и столбцами по сути является двумерным массивом.
- Вы можете читать непосредственно из диапазона листа в двухмерный массив всего за одну строку кода.
- Вы также можете записать из двумерного массива в диапазон всего за одну строку кода.
Источник
dk
MrExcel MVP
-
#2
I’d be very suprised if you could do this. You’d be better off using a variable array, or a custom function which returns the number of days in a given month.
-
#3
I need to revisit this question. There is a need for arrays of constants. I need to add some cells to a worksheet to show average, min, and max. The worksheet is quite asymetrical and the columns to be evaluated are not definable. Here is what I have been able to do as a workaround.
Code:
Dim Evaluation_Array As Variant
Evaluation_Array = Array(3, 4, 5, 6, 8, 11, 15)
For Each Sum_Column_Number In Evaluation_Array
Call Build_Evaluation_Cell(My_Worksheet, _
Sum_Column_Number, _
Sumation_Row, _
Top_Sumation, _
Bottom_Sumation)
Next
The subroutine (in part) adds a summing cell in a row for each of the columns specified. There is more to this, but I hope the code extract above will convey the general concept.
Evaluation_Array really should be an integer, not a variant, as should be Sum_Column_Number. The use of variant requires that the subroutine be declared with a variant rather than an integer.
The original post is approaching five years old now. Can an array of constants be declared?
-
#4
I don’t understand why you would need to do this.
What is the difference between defining this array as a constant, and just defining it by hardcoding the values in to be compiled at run time?
It makes no difference as far as I can see…
You can have the array as an integer, there is no problem there either…. so long as you know the array will be a predetermined length.
e.g.
Code:
option base 1
dim myarray(3) as integer
myarray(1) = 3 : myarray(2) = 4: myarray(3) = 5
Even if you don’t know it would be a pre-determined length, you can use the
keyword to extend the array as and when required.
Am I missing something here?
-
#5
Then again, why do you need the array of days in a month at all? Couldn’t you just use:
Code:
Dim monthnum As Integer
monthnum = 2
MsgBox Day(DateSerial(2006, monthnum + 1, 0))
or similar?
-
#6
Question: Why do we need to be able to declare an array of constants?
First, for the same reason that we need constants, we need an array of constants. And for all of those reasons. I don’t want to build it a run time, I want it predefined at compile time. I have some deadlines and don’t have time to entertain that discussion right now. Get a few books on software engineering and read about software design and constants. Read about writing software for flexibility, robustness and maintainability.
Please bear in mind that example code posted here is often a vehicle used to convey a complex idea. The simplest possible code segment that can convey the question is posed, the often huge amount of complexity behind it is deliberatly omitted. Because the quesion is simple does not mean that the needs are simple.
For now I take it that there is no declaration of constant arrays and will move on. I appreciate the time you took to respond and will leave this thread monitored.
-
#7
It’s not exactly the an array when it’s set as a constant, but the below has similar effects to what you ask:
Code:
Const z As String = "1, 2, 3, 4, 5, 6, 7"
Sub Test()
x = Split(z, ",")
For y = LBound(x) To UBound(x)
MsgBox x(y)
Next
End Sub
-
#8
First, for the same reason that we need constants, we need an array of constants. And for all of those reasons. I don’t want to build it a run time, I want it predefined at compile time. I have some deadlines and don’t have time to entertain that discussion right now. Get a few books on software engineering and read about software design and constants. Read about writing software for flexibility, robustness and maintainability.
I read your response with interest.
First and foremost, this is a discussion forum where people offer help to others for free. I am not being paid to sit here and read your posts, I do it for the love of helping people out.
If you read many of the posts on this forum, as I have, you will notice a trend with posts. That trend is that people often ask questions, under the presumption that the question they pose will help them fix their solution. All to often, however, it emerges that if more detail is given on the actual problem (as opposed to the solution they believe will fix it), other caveats to the problem can be unearthed that lead to the conclusion that the OP’s question can actually be reposed in another form, leading to an answer that satisfies what is the orginal issue.
I stated I did not understand why you would want an array of constants. To this point, I still don’t understand your intentions. If your motivation was made clearer, then as you say, we could cut through this whole portion of analysis and simply offer you solutions that achieve what you want.
I have to take significant issue with your tone. You know nothing about anyones software development history on this board. As it happens I am a graduate in Computer Science from a top UK university. I do not need your patronising advice on getting some ‘books on software design’. I am very aware of software design principles. I work as a software designer here in London, with Java and C++, as well as a little dabbling in VBA. I have answered numerous posts on this forum with no complaints from the OP’s who have got things working as a result. You cannot declare a constant array in VBA. I could have left it there, but decided to try and explore your problem and offer alternative solutions that could act as a workaround for you. Sure constants are only evaluated once as opposed to everytime a variable is used. Yes, there is an overhead to that, but if its important as you say it is, you can use a variable to hold the array, and then use some (now its my time to get patronising) common sense to leave the array alone at run time, and therefore protect its values.
Furthermore, with this high and mighty attitude you seem to have, I would expect you would get little help from the people on this board. This is a community that involves mutual respect, and a culture of helpfulness and learning. Both myself, and Oaktree (a Microsoft most valued professional) have taken the time out of our lives to attempt to address your problem, to try and talk you through your thought process so as to ascertain not only what you want, but why you want it as well. Frankly I find your consequent posts abhorrently patronising and full of negativity.
My advice — change your attitude, and fast, else you’ll find yourself going down in a very negative fashion not only on this medium, but in life in general.
Good day to you.
-
#9
Hi bkelly
1. I agree with you. We should be able to define constant arrays. Whenever the language allows it I define most of the constants at the beginning of the modules, outside the routines.
2 . It is not true what you say: «The use of variant requires that the subroutine be declared with a variant rather than an integer.»
You can (should) use a type conversion function and define the subroutine properly.
Try this:
Code:
Sub ConvType()
Dim v As Variant
v = 2
Call paramtype(CInt(v))
End Sub
Sub paramtype(i As Integer)
MsgBox i & ", " & TypeName(i)
End Sub
3. You can use a workaround like BJungheim’s. This will let you define the constant array at the beginning of the module
Code:
Const sArr As String = "1,3,5,7"
Sub a()
Dim v
For Each v In Split(sArr, ",")
MsgBox CInt(v)
Next
End Sub
4 — It might be better if along with a syntax question you would explain your problem.
There may be other ways of doing what you want that may be more efficient and easier to implement.
In this case, although I don’t have enough information about your problem, I got the feeling that maybe you could use a multiarea range.
If you had explained your problem better, I might be able suggest it or understand that it makes no sense
5. Last but not least:
I have some deadlines and don’t have time to entertain that discussion right now. Get a few books on software engineering and read about software design and constants. Read about writing software for flexibility, robustness and maintainability.
Let me tell you that what you wrote is very unpolite and even a bit aggressive.
As you know we all try to help each other in this board. The attitude from one member towards the others is expected to be polite, even friendly.
An attitude like the one you displayed, if meant, is not welcome.Best regards
PGC
-
#10
Hi pcg,
I just want to point out that it’s Bryan Kelly who is being so rude, and not Hedges.
Массивы в VBA Excel: одномерные, многомерные и динамические. Объявление и использование массивов. Операторы Public, Dim и ReDim. Функции Array, LBound, UBound.
Массивы – это множества однотипных элементов, имеющих одно имя и отличающиеся друг от друга индексами. Они могут быть одномерными (линейными), многомерными и динамическими. Массивы в VBA Excel, как и другие переменные, объявляются с помощью операторов Dim и Public. Для изменения размерности динамических массивов используется оператор ReDim. Массивы с заранее объявленной размерностью называют статическими.
Одномерные массивы
Объявление одномерных (линейных) статических массивов в VBA Excel:
Public Massiv1(9) As Integer Dim Massiv2(1 To 9) As String |
В первом случае публичный массив содержит 10 элементов от 0 до 9 (нижний индекс по умолчанию — 0, верхний индекс — 9), а во втором случае локальный массив содержит 9 элементов от 1 до 9.
По умолчанию VBA Excel считает в массивах нижним индексом нуль, но, при желании, можно сделать нижним индексом по умолчанию единицу, добавив в самом начале модуля объявление «Option Base 1».
Многомерные массивы
Объявление многомерных статических массивов в VBA Excel аналогично объявлению одномерных массивов, но с добавлением размерностей дополнительных измерений через запятую:
‘Массив двухмерный Public Massiv1(3, 6) As Integer ‘Массив трехмерный Dim Massiv2(1 To 6, 1 To 8, 1 To 5) As String ‘Массив четырехмерный Dim Massiv3(9, 9, 9, 9) As Date |
Третий массив состоит из 10000 элементов — 10×10×10×10.
Динамические массивы
Динамические массивы в VBA Excel, в отличие от статических, объявляются без указания размерности:
Public Massiv1() As Integer Dim Massiv2() As String |
Такие массивы используются, когда заранее неизвестна размерность, которая определяется в процессе выполнения программы. Когда нужная размерность массива становится известна, она в VBA Excel переопределяется с помощью оператора ReDim:
Public Massiv1() As Integer Dim Massiv2() As String ReDim Massiv1(1 To 20) ReDim Massiv2(3, 5, 4) |
При переопределении размерности массива вместо верхнего индекса можно использовать переменную:
Dim Massiv1() as Variant, x As Integer x = 20 ReDim Massiv1(1 To x) |
Переопределять размерность динамических массивов в процессе работы программы можно неоднократно, как по количеству измерений, так и по количеству элементов в измерении.
С помощью оператора ReDim невозможно изменить обычный массив, объявленный с заранее заданной размерностью. Попытка переопределить размерность такого массива вызовет ошибку компиляции с сообщением: Array already dimensioned (Массив уже измерен).
При переопределении размерности динамических массивов в VBA Excel теряются значения их элементов. Чтобы сохранить значения, используйте оператор Preserve:
Dim Massiv1() As String ——— операторы ——— ReDim Massiv1(5, 2, 3) ——— операторы ——— ReDim Preserve Massiv1(5, 2, 7) |
Обратите внимание!
Переопределить с оператором Preserve можно только последнюю размерность динамического массива. Это недоработка разработчиков, которая сохранилась и в VBA Excel 2016. Без оператора Preserve можно переопределить все размерности.
Максимальный размер
Размер массива – это произведение длин всех его измерений. Он представляет собой общее количество элементов, содержащихся в данный момент в массиве.
По информации с сайта разработчиков, максимальный размер массивов зависит от операционной системы и доступного объема памяти. Использование массивов, размер которых превышает объем доступной оперативной памяти компьютера, приводит к снижению скорости, поскольку системе необходимо выполнять запись данных и чтение с диска.
Использование массивов
Приведу два примера, где не обойтись без массивов.
1. Как известно, функция Split возвращает одномерный массив подстрок, извлеченных из первоначальной строки с разделителями. Эти данные присваиваются заранее объявленному строковому (As String) одномерному динамическому массиву. Размерность устанавливается автоматически в зависимости от количества подстрок.
2. Данные в массивах обрабатываются значительно быстрее, чем в ячейках рабочего листа. Построчную обработку информации в таблице Excel можно наблюдать визуально по мерцаниям экрана, если его обновление (Application.ScreenUpdating) не отключено. Чтобы ускорить работу кода, можно значения из диапазона ячеек предварительно загрузить в динамический массив с помощью оператора присваивания (=). Размерность массива установится автоматически. После обработки данных в массиве кодом VBA полученные результаты выгружаются обратно на рабочий лист Excel. Обратите внимание, что загрузить значения в диапазон ячеек рабочего листа через оператор присваивания (=) можно только из двумерного массива.
Функции Array, LBound, UBound
Функция Array
Функция Array возвращает массив элементов типа Variant из первоначального списка элементов, перечисленных через запятую. Нумерация элементов в массиве начинается с нуля. Обратиться к элементу массива можно, указав в скобках его номер (индекс).
Sub Test1() Dim a() As Variant a = Array(«text», 25, «solo», 35.62, «stop») MsgBox a(0) & vbNewLine & a(1) & vbNewLine _ & a(2) & vbNewLine & a(3) & vbNewLine & a(4) End Sub |
Скопируйте код в модуль VBA Excel и запустите его на выполнение. Информационное сообщение MsgBox покажет значения массива, извлеченные по индексу.
Функция LBound
Функция LBound возвращает значение типа Long, равное наименьшему (нижнему) доступному индексу в указанном измерении массива.
Синтаксис:
LBound (arrayname[, dimension])
- arrayname — это имя переменной массива, является обязательным аргументом;
- dimension — это номер измерения массива, необязательный аргумент, по умолчанию принимает значение 1.
Наименьший индекс по-умолчанию может быть равен 0 или 1 в зависимости от настроек оператора Option Base. Нижняя граница архива, полученного с помощью функции Array, всегда равна 0.
При объявлении переменных массивов или переопределении их размерности наименьшие индексы могут быть любыми целыми числами, в том числе отрицательными.
Функция UBound
Функция UBound возвращает значение типа Long, равное наибольшему (верхнему) доступному индексу в указанном измерении массива.
Синтаксис:
UBound( arrayname[, dimension])
- arrayname — это имя переменной массива, является обязательным аргументом;
- dimension — это номер измерения массива, необязательный аргумент, по умолчанию принимает значение 1.
Функция UBound используется вместе с функцией LBound для определения размера массива.
Sub Test2() Dim a(—2 To 53) As String MsgBox «Наименьший индекс = « & LBound(a) & _ vbNewLine & «Наибольший индекс = « & UBound(a) End Sub |
Скопируйте код в модуль VBA Excel и запустите его на выполнение. Информационное сообщение MsgBox покажет значения наименьшего и наибольшего индекса переменной массива a.
Обход массива циклом
Обход одномерного массива циклом For… Next, в котором для определения границ массива используются функции UBound и LBound:
Sub Test3() Dim a() As Variant, i As Long a = Array(«text», 25, «solo», 35.62, «stop») For i = LBound(a) To UBound(a) Debug.Print «a(« & i & «) = « & a(i) Next End Sub |
Результат работы цикла вы увидите в окне Immediate.
Очистка (обнуление) массивов
Первый способ
Очистить любой массив, статический или динамический, без использования цикла можно с помощью оператора Erase. Термин «обнуление» можно применить только к массиву числового типа.
Dim Massiv1(4, 3) As String, Massiv2() As Variant ——— операторы ——— ‘переопределяем динамический массив ReDim Massiv2(2, 5, 3) ——— операторы ——— ‘очищаем массивы Erase Massiv1 Erase Massiv2 |
Обратите внимание, что оба массива при таком способе очистки будут возвращены в исходное состояние, которое они имели сразу после объявления:
- статический Massiv1 сохранит размерность (4, 3);
- динамический Massiv2 не сохранит размерность ().
Второй способ
Динамический массив можно очистить (обнулить) без использования цикла с помощью оператора ReDim. Просто переопределите его с той же размерностью.
Dim Massiv() As Double ——— операторы ——— ‘переопределяем массив ReDim Massiv(5, 6, 8) ——— операторы ——— ‘очищаем массив ReDim Massiv(5, 6, 8) |
-
10-30-2004, 05:54 AM
#1
Solved: Declare a Constant Array
Hi,
Can I declare an array in a similar fashion to a constant so that the data can be used by separate elements of a userform and sent to a function for processing. I don’t want to put them on the Userform itself, if I can avoid it.
Something like the following
[VBA] Cols = Array(«A», «D», «G», «H»)Sub Test1()
‘Cols = Array(«A», «D», «G», «H»)
Range(Cols(0) & «3»).Select
End SubSub test2()
Dim Cols()
‘Cols = Array(«A», «D», «G», «H»)
For Each gc In GetCols(Cols)
msg = msg & gc & «, «
Next
MsgBox msg
End SubFunction GetCols(Cols() As Variant) As Variant
Dim MyCols()
ReDim MyCols(UBound(Cols))For i = 0 To UBound(Cols)
MyCols(i) = Range(Cols(i) & «:» & Cols(i)).Column()
Next
GetCols = MyColsEnd Function
[/VBA]
-
10-30-2004, 01:02 PM
#2
Hi MD,
I don’t believe that you can declare a Constant array.
Possible alternatives:
1. A Public array variable that you fill with a ‘starter’ routine.
2. Store the data in a worksheet.
-
10-31-2004, 10:29 PM
#3
How about a public function that returns the array. Function works just like any variables.
Try this.
[vba]
Public Function Arr()
Arr = Array(«a», «b», «c»)
End FunctionSub try()
For Each a In Arr
MsgBox a
Next a
End Sub
[/vba]
-
11-01-2004, 09:57 AM
#4
That’s pretty good Sixth Sense. If that were the method, as I sometimes find myself lacking options, you can add different qualifying lines to your code so you don’t have to keep writing multiple Public Functions. You can just call from the sub routine and assign them in your Function …
[vba]Option Explicit
Public Function Arr(test)
Select Case test
Case «yes»
Arr = Array(«a», «b», «c»)
Case «no»
Arr = Array(«d», «e», «f»)
End Select
End FunctionSub try()
Dim a As Variant, test As String
test = «no»
For Each a In Arr(test)
MsgBox a
Next a
End Sub[/vba]Change the ‘test = «no» ‘ to whatever you wanted, msgbox, returned value, whatever. Just thought I’d throw that out there, fwiw.
-
11-01-2004, 10:40 AM
#5
Hi,
Thanks to all. I’ve decided to use the following, (which works on my test form at least!)
MD
[VBA]
Function Arr(MySet As String)
Select Case MySet
Case Is = «A»
Arr = Array(«A», «B», «C», «D»)
Case Is = «B»
Arr = Array(«E», «F», «G», «H»)
Case Is = «C»
Arr = Array(«I», «J», «K», «L»)
End SelectEnd Function
Private Sub UserForm_Initialize()
For Each A In Arr(«B»)
ListBox1.AddItem A
Next
End Sub
[/VBA]
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
- BB code is On
- Smilies are On
- [IMG] code is On
- [VIDEO] code is On
- HTML code is Off
Forum Rules