Vba excel пустой ли массив
Массивы очень упрощают процесс программирования. Без них практически невозможно написать универсальную программу. Например, представьте себе, что вы манипулируете информацией о квартирах жилого дома. Вы объявляете переменные K1 - для первой квартиры, K2 - для второй и так далее. K1=54 будет означать, что площадь первой квартиры 54 кв.м., К2=72 и т.д. Теперь представим, что нам надо подсчитать общую площадь всех квартир в доме. Очевидно, что это что-то типа Total_S = K1+K2+. +Kn. В одном доме у нас 36 квартир, а в другом 144. Представляете бредовость процесса подобного программирования? Если в первом случае я должен буду использовать 36 отдельных переменных для вычисления общей площади, то для второго дома уже 144. Очень быстро вы придёте к мысли, что вам нужна переменная, состоящая из нумерованных ячеек. Тогда обретают смысл все те операторы циклов, входящие в состав любого языка программирования. Но об этом чуть позже.
Что такое массив
Массив - переменная, состоящая из некоторого количества однотипных элементов. У массива, как и у любой другой переменной, есть имя. А доступ к конкретному элементу массива осуществляется через указание в скобках после имени его индекса. Например, A(5) означает, что я обращаюсь к элементу с индексом 5 массива, имеющего имя A.
Типы массивов
Массивы в VBA и во многих других языках программирования делятся на 2 класса:
Фиксированные массивы . Такие массивы состоят из заранее известного количества элементов. Это количество определяется во время объявления массива и уже не может быть изменено в процессе его жизненного цикла. Вы, конечно же, сможете использовать меньшее количество элементов, но не существует способа увеличить количество элементов сверх объявленного.
Динамические массивы . Эти массивы можно "переобъявлять" в процессе жизненного цикла. То есть мы можем управлять количеством элементов динамических масивов в зависимости от наших потребностей. Это очень удобно, так как в подавляющем большинстве случаев программист не может заранее знать, с каким объёмом данных он столкнётся. Если вы собираетесь писать более-менее универсальные программы, то этот тип массивов определенно стоит изучить.
Объявление массивов
Объявление фиксированных массивов
Рекомендация : при объявлении массивов VBA я советую вам давать всем именам префикс " arr ". Я сторонник венгерской нотации.
Как мы видим, тут объявлено 2 одномерных массива arrTemp и arrTest . Одномерные массивы в программировании также часто называют векторами . Типом элементов первого массива является Long , второго массива - String . В этом типе синтаксиса в скобках указан максимальный индекс ( верхняя граница ) элемента массива. А что насчёт минимального индекса ( нижней границы ) массива? По-умолчанию минимальным индексом является ноль. В данном случае стандартное поведение интерпретатора языка VBA можно изменить при помощи оператора option base <0|1>. Option base 1 заставляет VBA считать нижней границей массива - единицу, а не ноль.
Таким образом, по-умолчанию массив arrTemp имеет 11 элементов - от 0 до 10. Но, если в начало модуля, в котором этот массив объявляется, вставить оператор Option Base 1 , то массив arrTemp будет иметь 10 элементов - от 1 до 10.
Помимо вышеуказанного вы вправе использовать следующий синтаксис, который НЕ зависит от option base <0|1>:
таким образом вы в явном виде указываете и нижнюю, и верхнюю границы. Как видите, нижняя граница совершенно не обязательно должна начинаться с 0 или 1. Более того, индексы границ могут принимать и отрицательные значения, главное чтобы нижняя была меньше верхней.
Помимо одномерных массивов, можно объявлять и массивы с размерностью больше единицы.
arrMulti - двумерный массив, а arrData3 - трёхмерный. Первый содержит 11*31=341 элемент, второй - 2*3*10=60 элементов. Теоретически допускается объявлять до 60 размерностей массива.
Какие типы данных могут стать элементами массива? Тут всё, как в шутке про фамилию еврея, - абсолютно любой тип данных годится на роль элемента массива, включая объектные типы, User Data Type , другие массивы (через тип Variant ). Если вы не указываете при объявлении тип данных массива, то предполагается, что этим типом является тип Variant .
Объявление динамических массивов
Динамические массивы объявляться так:
Однако, использовать их после такого объявления пока ещё нельзя. Необходимо выделить память под массив. Особенность работы с динамическим массивом как раз состоит в том, что программист отвечает за его своевременное расширение (усечение) в памяти. Для этого существует специальный оператор, который имеет следующий синтаксис:
ReDim [Preserve] varname(subscripts) [As Type]
После этого оператора, вы можете использовать элементы массива arrOpen с 0-го по 5-й. Всё, что мы говорили про оператор option base и нижнюю границу, верно и для динамических массивов. Предположим, что вы сохранили информацию в элементах 0-5 и у вас поспела новая порция информации для элементов 6-11. Чтобы разместить в данном массиве новые элементы и не потерять старые, вы должны сделать следующее:
то есть мы тут увеличиваем верхнюю границу массива и используем ключевое слово Preserve , чтобы во время этой операции не потерять текущее содержимое arrOpen , так как в противном случае (без слова Preserve ) массив будет расширен, а память заполнена нулями. Вы также вправе вообще не декларировать массив оператором Dim , а сделать это впервые через ReDim и там же указать лип элементов. Но, если вы в первом ReDim (или Dim ) указали определенный тип элементов, то в последующих операторах ReDim этот тип переопределён быть не может - возникнет ошибка на этапе компиляции проекта.
Изменение элементов массива
Пора бы нам уже научиться пользоваться нашими массивами - то есть записывать информацию в их элементы и считывать её оттуда. Это довольно просто:
Как и с обычными переменными запись информации в элемент массива происходит через оператор присваивания (=), но указанием индекса элемента массива.
Чтение элементов массива
Определение границ массива
В подпрограммах часто приходится иметь дело с массивами, которые переданы вам в качестве параметра (как это сделать показано ниже), поэтому в этом случае очень актуален вопрос определения нижней и верхней границ индекса массива. Для этого в языке предусмотрены 2 функции: LBound и UBound . Первая возвращает нижнюю границу индекса, вторая - верхнюю.
LBound( array [, dimension])
UBound( array [, dimension])
Для одномерных массивов параметр dimension можно не указывать. Для многомерных массивов его указывать необходимо. Кстати, это означает, что, если вы точно не знаете, с каким массивом имеете дело, но необходимо узнать его первую размерность, то лучше использовать вариант UBound(arrTemp,1) , а не UBound(arrTemp) , так как последний вариант вызовет ошибку, если массив окажется многомерным.
Если вы ошибётесь с указанием правильного индекса массива, то возникнет ошибка периода исполнения с кодом 9. Эта же ошибка возникнет, если вы в функции LBound / UBound укажете несуществующую размерность массива (например, 3 для двумерного массива).
Перебор элементов массива
Собственно массивы нужны для того, чтобы хранить в них однотипную информацию и перебирать их в цикле. Как правило, алгоритм делает что-то полезное с одним элементом массива, а цикл повторяет эти типовые действия для всех элементов массива.
Наиболее удобный оператор цикла для перебора элементов массива - это безусловно For . Next .
так же есть способ не заботиться об определении нижней и верхней границ, если алгоритм не требует от нас знания текущего индекса массива:
Вы, конечно, можете перебирать массив и в других типах циклов Do . Loop , но, право, смысла и удобства в этом не много. По крайней мере я не сталкивался, кажется, с ситуациями, когда для перебора массива цикл For не подошёл.
Передача массивов в подпрограммы
Массивы удобнее всего передавать в подпрограммы в виде параметра типа Variant .
Обратите внимание, что функции GetResult в качестве параметра передаются массивы. При чём, в первом случае это массив с типом элементов Long , а во втором - String . За счёт того, что внутри функции используются переменные типа Variant , то сначала функция нам возвращает сумму элементов массива arrIntegers , а во втором результат сложения (конкатенации) строк массива arrStrings . Кроме того, параметр parArray не описан как массив ( parArray As Variant ), но мы внутри функции GetResult ведём себя с ним, как с массивом ( For Each Element In parArray )! Это возможно, так как переменные типа Variant умеют определять, что им присваивается и вести себя далее в соответствии с тем, что они содержат. Если переменной parArray присвоили массив (через вызов функции - строки 17 и 18), то она себя будет вести как массив.
Массив с элементами типа массив
Продемонстрируем, как можно хранить в качестве элементов массива другие массивы.
Результат отладочной печати:
Функция Array
Данная функция полезна для создания справочных массивов. Она возвращает переменную типа Variant , содержащую одномерный массив с типом элементов Variant .
Array( arglist )
Вызов функции без параметров приведёт к возврату массива нулевой длинны. При этом будет наблюдаться интересный эффект LBound вернёт вам 0, а UBound вернёт -1, то есть верхняя граница окажется меньше нижней границы.
Функция Split
Split возвращает одномерный массив, содержащий подстроки, из строкового выражении с учётом указанного разделителя
Split(expression[, delimiter[, limit[, compare]]])
expression - строковое выражение, содержащая подстроки и разделители. Обязательный параметр.
delimiter - текстовый разделитель. Необязательный параметр. Если опущен, то предполагается, что разделителем является символ пробела.
limit - количество подстрок, которое необходимо вернуть. -1 или отсутствие параметра означает, что вернуть надо все подстроки.
compare - константа, указывающая тип сравнения для символов разделителей. 1 - текстовое сравнение (без учёта регистра), 0 - бинарное сравнение (с учётом регистра).
Результат выглядит так:
Если вы в качестве разделителя укажете пустую строку, то на выходе получите массив, состоящий из одного элемента. Кстати, split всегда возвращает массив с нулевой нижней границей вне всякой зависимости от наличия option base 1 .
Нюансы работы с динамическими массивами
Неинициализированный массив
У динамического массива есть такое промежуточное состояние, когда он уже объявлен, но ещё не содержит никаких элементов.
То есть у переменной динамического массива есть такое состояние, когда мы не можем воспользоваться вспомогательными функциями LBound / UBound для определения его (массива) статуса. Это особенно надо учитывать, когда вы пишите подпрограммы, работающие с массивами. Прежде чем работать (перебирать) массив необходимо убедиться, что он проинициализирован, в противном случае программа вылетит с ошибкой 9.
Для этого я предлагаю пользоваться функцией подобной нижеописанной IsNotEmptyArray :
Расширение массива
Как правило, расширять динамический массив приходится в цикле. Возможны 2 стратегии: расширение на 1 элемент, как только в этом есть необходимость (назовём это эластичным расширением), и расширение авансом, когда вы увеличиваете верхнюю границу скачками, скажем сразу на 100 элементов. Реализовав оба варианта, я для себя сделал вывод, что авансовое расширение получилось и компактнее, и работает быстрее, так как операция расширения, вообще говоря, затратна и, чем реже вызывается, тем лучше.
Авансовый метод вышел даже компактнее
Удаление массива
Существует оператор Erase , который полностью освобождает память из-под динамического массива. Будучи вызванным для статического массива он его обнуляет, а если он строковый, то элементам присваивается пустые строки.
Получение массива на основе диапазона Excel
Самый эффективный по скорости способ получить содержимое диапазона Excel для манипулирования в VBA - это скопировать его в массив с элементами Variant. Делается так:
Даже, если вы передаёте в массив столбец или строку, получаемый массив всегда будет иметь 2 измерения. Измерение 1 отвечает за строки, измерение 2 - за столбцы. То есть ячейка C5 будет в элементе arrTemp(5,3) . Нижняя граница таких массивов всегда будет начинаться с единицы.
Дополнительные источники
В качестве источника дополнительной информации по массивам я могу порекомендовать замечательный, исчерпывающий ресурс Чарльза Пирсона (Charles H. Pearson). Его сайт следует штудировать всем, кто серьёзно осваивает VBA. Конкретно по массивам там огромное количество готовых подпрограмм для работы с ними, исходные коды, снабженные подробнейшими комментариями, продвинутые объяснения для копающих в глубину. Без преувеличения великолепный ресурс!
Я хочу проверить наличие пустых массивов. Google дал мне различные решения, но ничего не помогло. Возможно я не применяю их правильно.
поскольку sFile пусто. Есть ли способ избежать этого?
Поскольку вы имеете дело со строковым массивом, рассматривали ли вы Join?
Перейти с тройным негативом:
В VB по любой причине Not myArray возвращает указатель SafeArray. Для неинициализированных массивов это возвращает -1. Вы можете Not это XOR это с -1, таким образом, возвращая ноль, если вы предпочитаете.
Если вы протестируете функцию массива, она будет работать для всех границ:
Здесь я вижу похожие ответы . но не мои .
Вот как я, к сожалению, собираюсь разобраться с этим . Мне нравится подход len (join (arr))> 0, но он не сработал бы, если бы массив представлял собой массив пустых строк .
Когда я пишу VBA, в моей голове есть такое предложение: "Может быть, так легко, но . "
Вот то, что я принял это:
Этот код не делает то, что вы ожидаете:
Если вы передадите пустую строку ( "" ) или vbNullString в Dir , он вернет имя первого файла в текущем пути к каталогу (путь, возвращаемый CurDir$ ). Таким образом, если SigString пусто, ваше условие If будет оценено как True , поскольку Dir вернет непустую строку (имя первого файла в текущем каталоге), и будет вызвано GetBoiler . И если SigString пусто, вызов fso.GetFile не удастся.
Вы должны либо изменить свое условие, чтобы убедиться, что SigString не пусто, либо использовать метод FileSystemObject.FileExists вместо Dir для проверки существования файла. Dir сложно использовать именно потому, что он делает то, чего вы не ожидаете. Лично я бы использовал Scripting.FileSystemObject вместо Dir , потому что нет ничего смешного ( FileExists возвращает True , если файл существует, и, ну, False , если его нет). Более того, FileExists выражает намерение вашего кода гораздо яснее, чем Dir .
Метод 1: сначала убедитесь, что SigString не пусто
Метод 2: Используйте метод FileSystemObject.FileExists
Я просто вставляю код под код великого Чипа Пирсона. Это работает шарм.
Вот его страница о функциях массива .
Функция ЕСЛИ в Excel: если ячейка содержит определенный текст - формула ЕСЛИ частичного совпадения
Я хочу проверить наличие пустых массивов. Google дал мне разные решения, но ничего не помогло. Может я неправильно их применяю.
поскольку sFile пустой. Есть ли способ избежать этого?
- 7 Ознакомьтесь с modArraySupport, полезным набором процедур от Чипа Пирсона для поддержки обработки массивов. IsArrayEmpty делает что хотите.
- Если TypeName (FileNamesList) = "Empty", то
Когда вы имеете дело со строковым массивом, рассматривали ли вы возможность соединения?
- 10 да это коротко. но потенциально он делает много ненужной работы.
- 1 @VBOG Хотите уточнить?
- 1 @Remou. Не FileNamesList массив? Разве вы не должны использовать Ubound вместо Len?
- 4 @VBOG Нет, потому что JOIN только что создал строку из массива.
- 3 Загвоздка в том, что это не работает, если у меня есть массив пустых строк . На самом деле это не говорит мне, был ли массив инициализирован.
Сделайте тройной минус:
В VB по любой причине Not myArray возвращает указатель SafeArray. Для неинициализированных массивов возвращается -1. Вы можете Not это для XOR с -1, таким образом возвращая ноль, если хотите.
- 4 Замечательное решение. Никогда не знал об этом взломе. Ура!
- Хороший трюк, +1 от меня, но, к сожалению, я не могу использовать это как часть функции, так как получаю ошибку времени выполнения 13, несоответствие типа Function isArrayInitialized2(Arr As Variant) As Boolean If (Not Arr) = -1 Then isArrayInitialized2 = False Else isArrayInitialized2 = True End Function
- @nkatsar вам нужно передать Arr как Arr ()
Если вы протестируете функцию массива, она будет работать для всех границ:
- 3 Неплохо, но примерьте arr определяется как это Dim arr() As String : arr = Split('') : Debug.Print IsVarArrayEmpty(arr) . Это возвращается False , но, судя по всему, arr является пустой массив (или как его еще назвать?), как ни странно, UBound(arr)=-1 а также LBound(arr)=0 . Эта проблема решена в IsArrayEmpty Чипа Пирсона. Вот почему я связался с ним в своем комментарии к вопросу.
- К сожалению, существует неопределенный массив, когда UBound выдает ошибку. Также есть пустой массив, где длина находится как и в любом другом случае: UBound (-1) - LBound (0) = 0
- Привет, если у вас база 0, ваш массив может добавить один элемент с индексом = 0. Это работает, если вы не устанавливаете массив, но не используете redim arr (0). В этом случае ваше решение не работает. Вам нужно проверить, если Ubound (arr) = 0 и len (Join (arr)) = 0. Это часть ответа @BBQ Chef
Я вижу здесь похожие ответы . но не мои .
Вот для чего я это приспособил:
Этот код не делает того, что вы ожидаете:
Если вы передадите пустую строку ( '' ) или vbNullString к Dir , он вернет имя первого файла в текущем пути к каталогу (путь, возвращаемый CurDir$ ). Так что если SigString пусто, твой If состояние будет оцениваться как True так как Dir вернет непустую строку (имя первого файла в текущем каталоге), а GetBoiler будет называться. И если SigString пусто, вызов fso.GetFile не удастся.
Вам следует либо изменить свое состояние, чтобы убедиться, что SigString не пусто, или используйте FileSystemObject.FileExists метод вместо Dir для проверки, существует ли файл. Dir сложно использовать именно потому, что он делает то, чего от него нельзя ожидать. Лично я бы использовал Scripting.FileSystemObject над Dir потому что нет смешного бизнеса ( FileExists возвращается True если файл существует, и, ну, False если нет). Более того, FileExists выражает намерение вашего кода намного яснее, чем Dir .
Метод 1. Убедитесь, что SigString не пусто сначала
Метод 2: используйте FileSystemObject.FileExists метод
Я просто вставляю ниже кода великого Чипа Пирсона. Это работает очаровательно.
Вот его страница о функциях массива.
Надеюсь, это поможет.
Auth был ближе всего, но его ответ выдает ошибку несоответствия типа.
Вот простое и полное решение:
Упрощенная проверка пустого массива:
- Это единственный способ сделать это, не задерживая ошибку. Невероятно.
Основываясь на ответе Ахута;
Проверить наличие пустого массива; is_empty = AryLen(some_array)=0
- 1 Если вы идете по этому маршруту, вы иметь тестировать UBound > LBound . В VBA вы можете запустить индекс массива, например, -5321 To -4112 . Просто одна из "забавных" причуд языка.
Вы можете использовать приведенную ниже функцию, чтобы проверить, пуст ли вариант или строковый массив в vba
Другой способ - сделать это раньше. Вы можете создать логическую переменную и установить для нее значение true после загрузки данных в массив. поэтому все, что вам действительно нужно, это простой оператор if, когда вы загружаете данные в массив.
Вот еще один способ сделать это. Я использовал его в некоторых случаях, и он работает.
Чтобы проверить, пуст ли массив байтов, самый простой способ - использовать функцию VBA StrPtr() .
Если массив байтов пуст, StrPtr() возвращается 0 ; в противном случае он возвращает ненулевое значение (однако не адрес к первому элементу).
Однако он работает только с байтовым массивом.
Может быть ubound вылетает и остается верным, и если ubound , оно пустое
Я обобщу проблему и вопрос, как задумано. Проверить задание на массив и отловить возможную ошибку
Конечно, он пропускает массивы со всеми отрицательными индексами или всеми> 1 . это вероятно? в странной стране, да.
Это обрабатывает ссылки с отрицательными числами и занимает меньше времени, чем некоторые другие варианты.
Вы можете проверить, пуст ли массив, получив общее количество элементов с помощью JScript VBArray() объект (работает с массивами вариантного типа, одномерными или многомерными):
Для меня это занимает около 0,3 мкс для каждого элемента + инициализация 15 мс, поэтому массив из 10M элементов занимает около 3 секунд. Та же функция может быть реализована через ScriptControl ActiveX (он недоступен в 64-битных версиях MS Office, поэтому вы можете использовать обходной путь, подобный этому).
Вы можете проверить его количество.
Вот Сид это массив.
Надеюсь, это поможет. Хорошего дня!
Другое решение для проверки пустого массива
Или, если вы уже знаете, что LBound равен 0
Это может быть быстрее, чем join (). (А с отрицательными показателями не проверял)
Вот мой образец для фильтрации двух строковых массивов, чтобы они не использовали одни и те же строки.
Массив — это набор значений, которые являются терминами элементы, логически взаимосвязаны друг с другом. Например, массив может состоять из числа учащихся в словаре грамматики. Каждый элемент массива — это количество учащихся одного уровня. Аналогичным образом массив может состоять из оценок учащегося для класса. Каждый элемент массива является однозначным.
Для хранения каждого элемента данных можно использовать отдельные переменные. Например, если наше приложение анализирует оценки учащихся, можно использовать отдельную переменную для каждой категории учащегося, например englishGrade1 , и englishGrade2 т. д. Этот подход имеет три основных ограничения:
- Во время разработки мы должны знать, сколько оценок нужно обменять.
- Обработка большого количества оценок быстро оказывается неудобной. Это, в свою очередь, значительно повышает вероятность возникновения серьезных ошибок в приложении.
- Его сложно поддерживать. Для каждого нового добавляемого класса необходимо, чтобы приложение было изменено, перекомпилировано и развернуто.
Используя массив, можно ссылаться на эти связанные значения по одному и тому же имени и использовать число, которое называется индексом или подиндексом для обозначения отдельного элемента в зависимости от его позиции в массиве. Индексы в диапазоне от 0 до 1 меньше, чем общее число элементов в массиве. при использовании синтаксиса Visual Basic для определения размера массива указывается его самый высокий индекс, а не общее число элементов в массиве. Можно работать с массивом как с единицей, а возможность итерации элементов освобождает вас от необходимости знать, сколько элементов оно содержит во время разработки.
Несколько простых примеров перед подробным описанием:
Элементы массива в простом массиве
Давайте создадим массив с именем students для хранения числа учащихся в каждом классе в школе. Индексы элементов находятся в диапазоне от 0 до 6. Использование этого массива проще, чем объявление семи переменных.
На следующем рисунке показан students массив. Для каждого элемента массива:
индекс элемента представляет школьный класс (индекс 0 представляет детский сад);
значение, содержащееся в элементе, представляет число учеников в этом классе.
в следующем примере содержится код Visual Basic, который создает и использует массив:
В этом примере выполняется три вещи:
- Он объявляет students массив с семью элементами. Число 6 в объявлении массива указывает последний индекс в массиве; он меньше, чем число элементов в массиве.
- Он присваивает значения каждому элементу в массиве. Доступ к элементам массива осуществляется с помощью имени массива, включая индекс отдельного элемента в круглых скобках.
- В нем перечисляются все значения массива. В примере используется For оператор для доступа к каждому элементу массива по номеру индекса.
students Массив в предыдущем примере является одномерным массивом, так как он использует один индекс. Массив, использующий более одного индекса или подстрочного, называется многомерным. Дополнительные сведения см. в остальной части этой статьи и в разделе измерения массива в Visual Basic.
Создание массива
Размер массива можно определить несколькими способами.
Размер можно указать при объявлении массива:
Можно использовать предложение, New чтобы указать размер массива при его создании:
При наличии существующего массива его размер можно переопределить с помощью ReDim инструкции. Можно указать, что ReDim инструкция сохранит значения в массиве, или можно указать, что он создает пустой массив. В приведенном ниже примере показаны различные варианты использования оператора ReDim для изменения размера существующего массива.
Дополнительные сведения см. в описании оператора ReDim.
Сохранение значений в массиве
К любой позиции в массиве можно получить доступ, используя индекс типа Integer . Вы можете сохранять и извлекать значения массива, ссылаясь на позицию в нем с помощью индекса, заключенного в скобки. Индексы для многомерных массивов разделяются запятыми (,). Для каждого измерения массива требуется один индекс.
В следующем примере показаны некоторые инструкции, которые хранят и извлекают значения в массивах.
Заполнение массива литералами массива
С помощью литерала массива можно заполнить массив начальным набором значений во время его создания. Литерал массива состоит из списка разделенных запятыми значений, заключенных в фигурные скобки ( <> ).
При создании массива с помощью литерала массива можно либо указать тип массива, либо использовать определение типа для задания типа массива. В следующем примере показаны оба варианта.
При использовании вывода типа тип массива определяется главным типом в списке литеральных значений. Главным типом является тип, к которому могут расширяться все другие типы в массиве. Если такой уникальный тип нельзя определить, то главным будет тип, до которого можно сузить все другие типы массива. Если ни один из указанных уникальных типов нельзя определить, главным типом будет Object . Например, если список значений для литерала массива содержит значения типов Integer , Long и Double , результирующий массив будет иметь тип Double . Поскольку Integer и Long расширяются только до Double , Double является главным типом. Для получения дополнительной информации см. Widening and Narrowing Conversions.
Вывод типа можно использовать только для массивов, определенных как локальные переменные в члене типа. Если явное определение типа отсутствует, массивы, определенные с литералами массива на уровне класса, имеют тип Object[] . Дополнительные сведения см. в разделе определение локального типа.
Обратите внимание, что в предыдущем примере определяется values как массив типа, Double хотя все литералы массива имеют тип Integer . Этот массив можно создать, так как значения в литерале массива могут расширяться до Double значений.
Можно также создать и заполнить многомерный массив с помощью вложенных литералов массива. Вложенные литералы массива должны иметь ряд измерений, которые соответствуют результирующему массиву. В следующем примере создается двухмерный массив целых чисел с помощью вложенных литералов массива.
При использовании вложенных литералов массива для создания и заполнения массива возникает ошибка, если число элементов в литералах вложенных массивов не совпадает. Ошибка также возникает, если вы явно объявили переменную массива так, чтобы число измерений не превышало литералы массива.
Точно так же, как и для одномерные массивов, при создании многомерного массива с вложенными литералами массива можно полагаться на определение типа. Выводимый тип является главным типом для всех значений во всех литералах массива для всех уровней вложенности. В следующем примере создается двухмерный массив типа Double[,] из значений типа Integer и Double .
Дополнительные примеры можно найти в статье How to: Initialize an Array Variable in Visual Basic (Практическое руководство. Инициализация переменной массива в Visual Basic).
Проход по массиву
При итерации по массиву вы обращаетесь к каждому элементу в массиве от самого низкого индекса к верхнему или от самого низкого. Как правило, используйте для. Next или For Each. Оператор Next для итерации элементов массива. Если вы не знакомы с верхними границами массива, можно вызвать Array.GetUpperBound метод, чтобы получить наибольшее значение индекса. Хотя наименьшее значение индекса почти всегда равно 0, можно вызвать Array.GetLowerBound метод, чтобы получить наименьшее значение индекса.
В следующем примере выполняется итерация по одномерным массиву с помощью For. Next инструкции.
В следующем примере выполняется перебор многомерного массива с помощью For. Next инструкции. Метод GetUpperBound имеет параметр, который определяет измерение. GetUpperBound(0) Возвращает самый верхний индекс первого измерения и GetUpperBound(1) возвращает наибольший индекс второго измерения.
В следующем примере используется объект For Each. Оператор Nextдля итерации одномерного массива и двумерного массива.
Размер массива
Размер массива является произведением длин всех его измерений. Он представляет собой общее число элементов, в данный момент содержащихся в массиве. Например, в следующем примере объявляется двухмерный массив с четырьмя элементами в каждом измерении. Как видно из выходных данных в примере, размер массива равен 16 (или (3 + 1) * (3 + 1).
Это обсуждение размера массива не применяется к массивам зубчатых размеров. Сведения о массивах немассивности и определении размера массива массивов см . в разделе массива массивов .
Размер массива можно определить с помощью свойства Array.Length. Длину каждого измерения многомерного массива можно узнать с помощью Array.GetLength метода.
Можно изменить размер переменной массива, назначив ей новый объект массива или используя инструкцию ReDim инструкции . В следующем примере оператор используется ReDim для изменения массива 100-element на массив 51-element.
Существует ряд особенностей, о которых следует помнить при работе с размером массива.
Примечания | |
---|---|
Длина измерения | Индекс каждого измерения основан на 0, что означает, что он находится в диапазоне от 0 до верхней границы. Таким образом, длина данного измерения больше, чем объявленная верхняя граница этого измерения. |
Ограничения длины | Длина каждого измерения массива ограничена максимальным значением Integer типа данных, которое равно Int32.MaxValue или (2 ^ 31)-1. Однако общий размер массива также ограничен доступной памятью в системе. При попытке инициализировать массив, размер которого превышает объем доступной памяти, среда выполнения создает исключение OutOfMemoryException . |
Размер и размер элемента | Размер массива не зависит от типа его элементов. Размер всегда представляет общее число элементов, а не число байтов, используемых в памяти. |
Потребление памяти | Небезопасно делать какие-либо предположения относительно способа хранения массива в памяти. Хранение зависит от разрядности платформы, поэтому один и тот же массив может занимать больше памяти в 64-разрядных системах, чем в 32-разрядных. В зависимости от конфигурации системы при инициализации массива среда CLR может использовать такие способы хранения, как упаковка элементов максимально близко друг к другу или выравнивание всех элементов по естественным аппаратным границам памяти. Кроме того, массив нуждается в хранении служебной информации, и размер этой информации возрастает при добавлении каждого измерения. |
Тип массива
Каждый массив имеет тип данных, который отличается от типа данных его элементов. Не существует единого типа данных, подходящего для всех массивов. Вместо этого тип данных массива определяется числом измерений ( рангом) массива и типом данных его элементов. Две переменные массива имеют один и тот же тип данных, только если они имеют одинаковый ранг и их элементы имеют один и тот же тип данных. Длины измерений массива не влияют на тип данных массива.
Каждый массив наследуется от класса System.Array, и вы можете объявить переменную типа Array , но не можете создать массив типа Array . Например, несмотря на то, что следующий код объявляет arr переменную как тип Array и вызывает Array.CreateInstance метод для создания экземпляра массива, тип массива доказывается на Object [].
Кроме того, оператор ReDim Array не может работать с переменной, объявленной с типом . По этим причинам, а для обеспечения безопасности типа рекомендуется объявлять каждый массив как конкретный тип.
Выяснить тип данных массива или его элементов можно несколькими способами.
- Можно вызвать GetType метод для переменной, чтобы получить Type объект, представляющий тип переменной во время выполнения. Объект Type содержит подробные сведения в своих свойствах и методах.
- Можно передать переменную в функцию, TypeName чтобы получить String с именем типа времени выполнения.
В следующем примере GetType TypeName для определения типа массива вызывается метод и функция. Тип массива — Byte(,) . Обратите внимание, что Type.BaseType свойство также указывает, что базовый тип массива байтов является Array классом.
Массивы как возвращаемые значения и параметры
Чтобы вернуть массив из процедуры Function , укажите тип данных массива и число измерений в качестве типа возвращаемого значения оператора Function. Внутри функции объявите локальную переменную массива с тем же числом измерений и типом данных. В оператор Return включите локальную переменную массива без скобок.
Чтобы задать массив в качестве параметра процедуры Sub или Function , определите параметр как массив с указанными типом данных и количеством измерений. В вызове процедуры передайте переменную массива с тем же типом данных и количеством измерений.
В следующем примере GetNumbers функция возвращает Integer() одномерный массив типа Integer . Процедура ShowNumbers принимает аргумент Integer() .
В следующем примере GetNumbersMultiDim функция возвращает Integer(,) , двухмерный массив типа Integer . Процедура ShowNumbersMultiDim принимает аргумент Integer(,) .
Массивы массивов
Иногда структура данных в приложении является двухмерной, но не прямоугольной. Например, массив можно использовать для хранения данных о высокой температуре каждого дня месяца. Первое измерение массива представляет месяц, но второе измерение представляет количество дней, а число дней в месяце является неравномерным. Немассивный массив, который также называется массивом массивов, предназначен для таких сценариев. Немассивный массив — это массив, элементы которого также являются массивами. Массив массивов и каждый элемент в нем могут иметь одно или несколько измерений.
В следующем примере используется массив месяцев, каждый элемент которого является массивом дней. В примере используется массив массива, поскольку разные месяцы имеют разное количество дней. В примере показано создание массива массивов, присвоение ему значений, а также извлечение и отображение его значений.
Массив массива является одномерным массивом, элементы которого содержат массивы. Таким образом, Array.Length свойство и Array.GetLength(0) метод возвращают количество элементов в одномерном массиве и выдают исключение, Array.GetLength(1) IndexOutOfRangeException так как массив массива не является многомерным. Число элементов в каждом подмассиве определяется путем извлечения значения свойства каждого подмассива Array.Length . В следующем примере показано, как определить количество элементов массива массивов.
Массивы нулевой длины
Visual Basic отличает неинициализированный массив (массив, значение которого равно Nothing ) и массив нулевой длины или пустой массив (массив без элементов). Неинициализированный массив — это тот, который не был измерен или имел присвоенные ему значения. Вот несколько примеров.
Массив нулевой длины объявляется с измерением-1. Вот несколько примеров.
Массив нулевой длины может потребоваться создать в указанных ниже случаях.
без риска возникновения NullReferenceException исключения код должен обращаться к членам Array класса, например Length или Rank , или вызвать функцию Visual Basic, например UBound .
Вы хотите, чтобы ваш код был простым, не требуя проверки в Nothing качестве специального случая.
Код взаимодействует с интерфейсом API, который требует передачи массива нулевой длины в одну или несколько процедур или возвращает массив нулевой длины из одной или нескольких процедур.
Разделение массива
В некоторых случаях может потребоваться разделить один массив на несколько массивов. Это включает определение точки или точек, в которых массив должен быть разделен, а затем спиттинг массив в два или более отдельных массива.
В этом разделе не рассматривается разделение одной строки на массив строк, основанный на каком-либо разделителе. Сведения о разбиении строки см. в описании String.Split метода.
Ниже приведены наиболее распространенные критерии разделения массива.
Количество элементов в массиве. Например, может потребоваться разделить массив больше, чем заданное число элементов, на несколько приблизительно равных частей. Для этой цели можно использовать значение, возвращаемое Array.Length Array.GetLength методом или.
Значение элемента, которое служит разделителем, указывающим место разделения массива. Можно выполнить поиск определенного значения, вызвав Array.FindIndex Array.FindLastIndex методы и.
После определения индекса или индексов, на которых массив должен быть разделен, можно создать отдельные массивы, вызвав Array.Copy метод.
В следующем примере массив разбивается на два массива приблизительно равного размера. (Если общее число элементов массива нечетное, первый массив содержит еще один элемент, чем второй.)
В следующем примере массив строк разбивается на два массива на основе наличия элемента, значение которого равно "zzz", которое служит разделителем массива. Новые массивы не включают элемент, содержащий разделитель.
Соединение массивов
Можно также объединить несколько массивов в один массив большего размера. Для этого также используется Array.Copy метод.
В этом разделе не обсуждается объединение массива строк в одну строку. Сведения о присоединении массива строк см. в описании String.Join метода.
Перед копированием элементов каждого массива в новый массив необходимо убедиться, что массив был инициализирован так, чтобы он был достаточно большим для размещения нового массива. Это можно сделать одним из двух способов.
- Используйте ReDim Preserve инструкцию для динамического расширения массива перед добавлением в него новых элементов. Это самый простой способ, но это может привести к снижению производительности и чрезмерному потреблению памяти при копировании больших массивов.
- Вычислите общее число элементов, необходимых для нового большого массива, а затем добавьте в него элементы каждого исходного массива.
В следующем примере используется второй подход к добавлению четырех массивов с десятью элементами в один массив.
Поскольку в этом случае исходные массивы невелики, можно также динамически расширять массив по мере добавления элементов каждого нового массива в него. Эту задачу решает следующий код.
Коллекции в качестве альтернативы массивам
Массивы удобнее всего использовать для создания фиксированного числа строго типизированных объектов и работы с ними. Коллекции предоставляют более гибкий способ работы с группами объектов. В отличие от массивов, требующих явного изменения размера массива ReDim инструкцией, коллекции растут и сжимаются динамически в соответствии с потребностями приложения.
при использовании ReDim для переизмерения массива Visual Basic создает новый массив и освобождает предыдущий. Это занимает время выполнения. Таким образом, если количество элементов, с которыми вы работаете, часто меняются, или вы не можете предсказать максимальное количество элементов, вы обычно получаете лучшую производительность, используя коллекцию.
Некоторые коллекции допускают назначение ключа любому объекту, который добавляется в коллекцию, чтобы в дальнейшем можно было быстро извлечь связанный с ключом объект из коллекции.
Объявление одномерных (линейных) статических массивов в VBA Excel:
В первом случае публичный массив содержит 10 элементов от 0 до 9 (нижний индекс по умолчанию — 0, верхний индекс — 9), а во втором случае локальный массив содержит 9 элементов от 1 до 9.
По умолчанию VBA Excel считает в массивах нижним индексом нуль, но, при желании, можно сделать нижним индексом по умолчанию единицу, добавив в самом начале модуля объявление «Option Base 1». Вместо верхнего индекса можно использовать переменную.
Многомерные массивы
Объявление многомерных статических массивов в VBA Excel аналогично объявлению одномерных массивов, но с добавлением размерностей дополнительных измерений через запятую:
Третий массив состоит из 10000 элементов — 10×10×10×10.
Динамические массивы
Динамические массивы в VBA Excel, в отличие от статических, объявляются без указания размерности:
Такие массивы используются, когда заранее неизвестна размерность, которая определяется в процессе выполнения программы. Когда нужная размерность массива становится известна, она в VBA Excel переопределяется с помощью оператора ReDim:
Переопределять размерность динамических массивов в процессе работы программы можно неоднократно, как по количеству измерений, так и по количеству элементов в измерении.
При переопределении размерности динамических массивов в VBA Excel теряются значения их элементов. Чтобы сохранить значения, используйте оператор Preserve:
Обратите внимание!Переопределить с оператором Preserve можно только последнюю размерность динамического массива. Это недоработка разработчиков, которая сохранилась и в VBA Excel 2016. Без оператора Preserve можно переопределить все размерности.
Максимальный размер
Размер массива – это произведение длин всех его измерений. Он представляет собой общее количество элементов, содержащихся в данный момент в массиве.
По информации с сайта разработчиков, максимальный размер массивов зависит от операционной системы и доступного объема памяти. Использование массивов, размер которых превышает объем доступной оперативной памяти компьютера, приводит к снижению скорости, поскольку системе необходимо выполнять запись данных и чтение с диска.
Использование массивов
Приведу два примера, где не обойтись без массивов.
1. Как известно, функция Split возвращает одномерный массив подстрок, извлеченных из первоначальной строки с разделителями. Эти данные присваиваются заранее объявленному строковому (As String) одномерному динамическому массиву. Размерность устанавливается автоматически в зависимости от количества подстрок.
2. Данные в массивах обрабатываются значительно быстрее, чем в ячейках рабочего листа. Построчную обработку информации в таблице Excel можно наблюдать визуально по мерцаниям экрана, если его обновление (Application.ScreenUpdating) не отключено. Чтобы ускорить работу кода, можно значения из диапазона ячеек предварительно загрузить в динамический массив с помощью оператора присваивания (=). Размерность массива установится автоматически. После обработки данных в массиве кодом VBA полученные результаты выгружаются обратно на рабочий лист Excel. Обратите внимание, что загрузить значения в диапазон ячеек рабочего листа через оператор присваивания (=) можно только из двумерного массива.
Функции Array, LBound, UBound
Функция Array
Функция Array возвращает массив элементов типа Variant из первоначального списка элементов, перечисленных через запятую. Нумерация элементов в массиве начинается с нуля. Обратиться к элементу массива можно, указав в скобках его номер (индекс).
Читайте также: