borro Пользователь Сообщений: 198 |
Здравствуйте. Расскажите или укажите, есть ли где сравнительное сопоставление трех понятий: массив, коллекция, словарь. Изменено: borro — 26.01.2017 02:14:53 |
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
Общее: по сути это все массивы. Но однозначно сказать что лучше, а что хуже нельзя. Все зависит от ситуации. P.S. Не забывайте отписывать в своих темах, в которых получили ответы: http://www.planetaexcel.ru/forum/index.php?PAGE_NAME=message&FID=1&TID=86715&TITLE_SEO=86715-kak-pol… Иначе есть шанс потом ответы не получить… Изменено: The_Prist — 25.01.2017 17:22:26 Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
borro Пользователь Сообщений: 198 |
|
borro Пользователь Сообщений: 198 |
Например, в некотором цикле будут собираться данные вида: Используя язык баз данных, пара значений «Артикул» и «Наименование» являются ключом для каждой строки массива данных. Вопрос — в данной задаче надо использовать какой из типов данных? |
Alex_ST Пользователь Сообщений: 2746 На лицо ужасный, добрый внутри |
С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!) |
Alex_ST Пользователь Сообщений: 2746 На лицо ужасный, добрый внутри |
ОГРОМНЫМ плюсом словарей является наличие в них методов Items и Keys возвращающих «одним махом» массивы ЗНАЧЕНИЙ и КЛЮЧЕЙ словаря С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!) |
Alex_ST Пользователь Сообщений: 2746 На лицо ужасный, добрый внутри |
#7 26.01.2017 16:15:31
Так что уникальное? Похоже, что Артикул? С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!) |
||
Sanja Пользователь Сообщений: 14838 |
#8 26.01.2017 16:30:00
Совсем не похоже.
Уникальна ПАРА (Артикул и Наименование), поэтому в данном случае лучше использовать составной ключ (Артикул&Наименование) Согласие есть продукт при полном непротивлении сторон. |
||||
Андрей VG Пользователь Сообщений: 11878 Excel 2016, 365 |
#9 26.01.2017 16:41:08 Доброе время суток.
, то это не приводит к автоматическому освобождению объектов-значений словаря. Они как-бы существуют вплодь до принудительного End, даже не до завершения метода, в котором создавался словарь. С коллекциями такого не происходит. |
||
Alex_ST Пользователь Сообщений: 2746 На лицо ужасный, добрый внутри |
#10 26.01.2017 16:47:34 Как-то я никогда особо освобождением памяти не заморачивался, хотя словари люблю и использую часто…
Никогда никаких проблем не возникало. Может быть, при таком связывании их просто нет? Изменено: Alex_ST — 26.01.2017 16:48:01 С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!) |
||
Андрей VG Пользователь Сообщений: 11878 Excel 2016, 365 |
Алексей, дело не в памяти — её хватало. А вот блокировка объектов не снималась. Пришлось делать вариант на Collection. Столкнулся не в Excel — в VBA IBM Rational System Architect. Изменено: Андрей VG — 26.01.2017 16:52:58 |
Hugo Пользователь Сообщений: 23251 |
#12 26.01.2017 20:36:52
— словарь для ключей с индексами, и массив для данных. Массив можно использовать тот же исходный. |
||
SuperCat Пользователь Сообщений: 2737 |
#13 26.01.2017 21:38:36
Интересно, а как это узнали? There is no knowledge that is not power |
||
Sanja Пользователь Сообщений: 14838 |
#14 26.01.2017 21:44:11
Я вот тоже буквально сегодня заметил нечто подобное. Если
словарь объявляется переменной (Dim dic1: Set dic1 = CreateObject(«Scripting.Dictionary»)), то наблюдаются какие-то глюки при попытке добавить НЕ уникальный ключ. С конструкцией With CreateObject(«Scripting.Dictionary») такого не происходит Изменено: Sanja — 26.01.2017 22:12:25 Согласие есть продукт при полном непротивлении сторон. |
||
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
#15 26.01.2017 21:49:52
Сёма, это-таки позднее связывание Раннее будет так:
А при случае использования With очищение памяти от объектов происходит более корректно, когда-то мы вроде это обсуждали уже. Это касается не только словарей, кстати. Изменено: The_Prist — 26.01.2017 21:51:49 Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
||||
Sanja Пользователь Сообщений: 14838 |
Ага, Семёёён Семёёёныч . Но факт наблюдался Согласие есть продукт при полном непротивлении сторон. |
Alex_ST Пользователь Сообщений: 2746 На лицо ужасный, добрый внутри |
#17 26.01.2017 22:09:30
Похоже, что Дмитрий у нас провидец… С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!) |
||
Андрей VG Пользователь Сообщений: 11878 Excel 2016, 365 |
#18 26.01.2017 22:13:49
Да есть в этом RSA возможность делать перекрёстную связь между объектами. Пользователь добавляет ссылку с родительского объекта на дочерний и у дочернего появляется в свойствах ссылка на родительский. Соответственно, в VBA нужно ссылки добавлять только с одной стороны, иначе, так как объекты (родительский и дочерний) при их создании открыты на редактирование, то невозможно сохранить не тот не другой. При загрузке же данных описание связей идёт как попало. Вот я и сделал поиск родительского объекта для дочерних через словарь. Сохранил родительские, очистил словарь. Стал сохранять дочерние с установленными ссылками на родительские, а RSA выбрасывает объект заблокирован. Переделал на коллекции — ушло. |
||
borro Пользователь Сообщений: 198 |
Доброго утра. Спасибо, Sanja за совет. Изменено: borro — 28.01.2017 10:14:27 |
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
#20 28.01.2017 11:19:13
А вопрос был какой последний?
Вы все же получили после этого ответ от Alex_ST — словари.
Но отписаться понятно-непонятно, оно-не оно уже не посчитали нужным. А между тем это проявление элементарной вежливости и уважения к отвечающим — отписаться ответившему: помогло — не помогло, понятно — не понятно и т.п. Чтобы все понимали имеет ли смысл дальше что-то предлагать или обсуждать. Т.к. Вы этого не делаете — тема развивается своим ходом, а Вас берут на заметку — типа это тот человек, который темы создает, ответы получает и сваливает. В результате что будет? Правильно. Вам просто перестанут отвечать, ибо потребительское отношение не нравится никому… Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
||||||
Hugo Пользователь Сообщений: 23251 |
#21 28.01.2017 11:50:10 Есть одна тонкость с
— Microsoft не обещает точное соответствие этих двух массивов, т.е. вываливать их рядом небезопасно. Изменено: Hugo — 28.01.2017 12:01:49 |
||
The_Prist Пользователь Сообщений: 14182 Профессиональная разработка приложений для MS Office |
Согласен с Игорем. Лучше создавать под это отдельный массив и в цикле выгружать туда сначала ключ, а потом соответствующий ключу элемент. Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
Юрий М Модератор Сообщений: 60575 Контакты см. в профиле |
Не совсем по теме, но близко )) |
webley Пользователь Сообщений: 1995 |
Юрий М, очень пригодилось, спасибо! |
Alex_ST Пользователь Сообщений: 2746 На лицо ужасный, добрый внутри |
#25 01.07.2022 14:53:39
Что-то я этот совет Юрия либо пропустил, либо просто забыл… С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!) |
||
Jack Famous Пользователь Сообщений: 10848 OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome |
#26 01.07.2022 17:10:51
они надёжнее, позволяют собирать новый или изменять текущий массив по имеющемуся в цикле индексу. Например, цикл по тысячам областей (фильтр столбца по видимым) нельзя делать через For Each, потому что будет ошибка. Честно говоря, есть сомнения по поводу скорости перебора словаря (коллекции не использую). Может, при позднем подключении, если только (я раннее использую). Тестов не вижу)) Изменено: Jack Famous — 01.07.2022 17:12:13 Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄ |
||
Jack Famous Пользователь Сообщений: 10848 OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome |
#27 01.07.2022 17:31:22 Действительно, перебор по индексам «в лоб» — не для словарей.
При раннем связывании, разница в соответствии «ключ-значение» в массивах при их получении из словаря, не замечена. При позднем — я не уверен.
Ссылки по теме: bedvit про порядок ключей-значений Изменено: Jack Famous — 04.07.2022 09:37:34 Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄ |
||
ZVI Пользователь Сообщений: 4328 |
#28 02.07.2022 14:57:49
Добрый день, Алексей.
Это утверждение некорректное, так как касается внутреннего механизма работы словаря, а не его документированного внешнего интерфейса (свойств и методов .Item, .Keys, .Values и др.) здесь . Изменено: ZVI — 02.07.2022 15:40:30 |
||||||
Jack Famous Пользователь Сообщений: 10848 OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome |
#29 04.07.2022 09:36:47 ZVI, приветствую! Всегда рад видеть вас в своих (и не только) темах
спасибо, согласен, оплошал, поправил
там были только тесты, а хотелось бы увидеть документальное подтверждение, ведь никакими тестами нельзя доказать правило, а можно только приближаться к нему. А вот когда в докУменте будет написано — другое дело. Во всяком случае, логика Виталия мне понятна: они сказали, что это аналог перловых таблиц, у перловых таблиц порядок сбора и хранения не соответствует, а значит и у словарей тоже. Изменено: Jack Famous — 04.07.2022 09:38:07 Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄ |
||||
ZVI Пользователь Сообщений: 4328 |
#30 04.07.2022 22:28:09 Добрый вечер, Алексей. |
Здравствуйте, AndreA SN,
У массивов и коллекций имеются следующие плюсы и минусы:
Массивы
Плюсы:
Более высокое быстродействие по сравнению с коллекциями.
Занимают меньше памяти, т.к. не требуют хранения ссылок на каждый элемент массива.
Минусы:
Занимают фиксированную область в памяти. При необходимости можно выделить для массива новую область памяти с помощью ReDim Preserve, но тогда системе понадобится потратить время на перенос значений из старой области памяти в новую.
Могут хранить элементы только одного типа, так как при хранении различных типов невозможно (или очень трудоемко) вычислить позицию n-ого элемента массива.
Коллекции
Плюсы:
Занимают произвольную область памяти, могут хранить любое разумное количество элементов.
Могут хранить элементы различных типов, так как позиция элемента коллекции в памяти не вычисляется, а берется из ссылки.
Минусы:
Работают медленно.
Занимают больше памяти, так как помимо самих элементов коллекции требуется хранить еще ссылки на эти элементы.
Особенности массивов и коллекций
(это не плюсы и не минусы, просто особенности)
Массив относится к типу данных значений. При копировании одной переменной типа массива в другую получаем новый независимый массив.
Коллекция — это ссылочный тип, поэтому…
- в первых, перед первым использованием необходимо выполнить выделение памяти под коллекцию и присвоить переменной ссылку на выделенную область памяти:
Visual Basic 1
Set my_collection = New Collection
- во-вторых, при присваивании одной переменной типа коллекции значения другой не создается новой независимой коллекции — вместо этого обе переменные будут хранить ссылку на одну и ту же область памяти.
С уважением,
Аксима
Содержание
- Зачем использовать массивы в VBA, когда есть коллекции?
- 3 ответа
- Excel VBA Collections
- What is a Collection in VBA?
- Collections Versus Arrays
- Scope of a Collection Object
- Create a Collection, Add Items, and Access Items
- Loop Through Collection
- Add Item to Collection
- VBA Coding Made Easy
- Remove an Item from Collection
- Count the Number of Items in a Collection
- Test Collection for a Specific Value
- Pass a Collection to a Sub / Function
- Return a Collection from a Function
- Convert a Collection to an Array
- Convert an Array into a Collection
- VBA Code Examples Add-in
Зачем использовать массивы в VBA, когда есть коллекции?
многие люди используют массивы массивов в Excel/VBA для хранения списка данных. Тем не менее, есть объект коллекции, который, на мой взгляд, МНОГО БОЛЬШЕ более удобен (в основном: не нужно повторно определять длину списка).
Итак, я искренне спрашиваю себя, не хватает ли чего-то? Почему другие люди все еще используют массивы для хранения списка данных? Это просто похмелье прошлого?
3 ответа
Несколько причин использовать массивы вместо коллекций (или словарей):
- вы можете легко передать массив в диапазон (и наоборот) с помощью Range(«A1:B12») = MyArray Коллекции
- могут хранить только уникальные ключи, тогда как массивы могут хранить любое значение
- коллекции должны хранить пару (ключ, значение), тогда как вы можете хранить все в массиве
Смотрите статью Chip Pearson о массивах для лучшего понимания
Лучше спросить, почему люди будут использовать коллекции над словарями (ok, коллекции являются стандартными VBA, тогда как вам нужно импортировать словари)
@CharlesWilliams ответ правильный: цикл через все значения массива быстрее, чем повторение коллекции или словаря: настолько, что я всегда использую метод Keys() или Items() словаря, когда мне нужно сделайте это — оба метода возвращают векторный массив.
Примечание. Я использую класс Dictionary гораздо больше, чем использование коллекций, метод Exists() слишком полезен.
Есть или, конечно, недостатки в сборниках и словарях. Один из них состоит в том, что массивы могут быть 2- или даже 3-мерными — намного лучшая структура данных для табличных данных. Вы можете хранить массивы как члены коллекции, но есть некоторые недостатки: один из них заключается в том, что вы не можете получать ссылку на элемент — если вы не используете arrItem = MyDictionary (strKey) , вы почти наверняка получит «ByVal» копию массива; это плохо, если ваши данные динамичны и могут быть изменены несколькими процессами. Это также медленно: много выделения и освобождения.
Хуже всего то, что я не доверяю VBA, чтобы освободить память, если у меня есть коллекция или словарь с массивами (или объектами!) в качестве элементов: не из-за пределов области, а не из Set objCollection = Nothing , даже не objDictionary.RemoveAll — трудно доказать, что проблема существует с ограниченным набором инструментов тестирования, доступным в VBE, но я видел достаточно утечек памяти в приложениях, которые использовали массивы в словарях, чтобы знать, что вам нужно быть осторожным. При этом я никогда не использую массив без команды Erase.
@JMax объяснил другой большой плюс для массивов: вы можете заполнить массив в одном «ударе» на листе и записать свою работу в один «хит».
Вы можете, конечно, получить лучшее из обоих миров, построив класс Indexed Array: двумерный массив со связанными объектами коллекции или словаря, хранящий какой-то идентификатор строки в качестве ключей, и порядковые числа строк в качестве данных Предметы.
Источник
Excel VBA Collections
In this Article
This tutorial will demonstrate how to use collections in VBA.
What is a Collection in VBA?
A collection is an object that holds a number of similar items that can easily be accessed and manipulated, even if there are a large number of items within the collection.
You can create your own collections, but VBA also comes with built in collections such as the Sheets Collection, which stores every sheet in the workbook. By using a For Each loop, you can iterate through each worksheet in the Sheets Collection.
You can also address a specific worksheet in the collection using the index value (it’s position in the collection), or the actual name of the worksheet:
As worksheets are added or deleted so the Sheets collection grows or shrinks in size.
Note that with VBA collections the index number begins with 1 not with 0.
Collections Versus Arrays
Arrays and Collections can both store data, however they have several notable differences:
- Arrays are multidimensional whereas collections are only single dimension. You can dimension an array with several dimensions e.g.
This creates an array of 10 rows with 2 columns, almost like a worksheet. A collection is effectively a single column.
- When you populate your array, you need a separate line of code to put a value into each element of the array. If you had a two-dimensional array you would actually need 2 lines of code – one line to address the first column and one line to address the second column. With the Collection object, you simply use the Add method so that the new item is just added into the collection and the index value is automatically adjusted to suit.
- If you need to delete an item of data then it is more complicated in the array. You can set the values of an element to a blank value, but the element itself still exists within the array. If you are using a For Next loop to iterate through the array, the loop will return a blank value, which will need coding to make sure that the blank value is ignored. In a collection you use the Add or Remove methods, and all the indexing and re-sizing is automatically taken care of. The item that has been removed disappears completely. Arrays are useful for a fixed size of data, but collections are better for where the quantity of data is liable to change.
- Collections are Read Only whereas array values can be changed using VBA. With a collection, you would have to remove the value to be changed first and then add in the new changed value.
- In an array, you can only use a single data type for the elements which is set when you dimension the array. However, in the array you can use custom data types that you have designed yourself. You could have a very complicated array structure using a custom data type which in turn has several custom data types below it. In a collection, you can add use data types of data for each item. You could have a numeric value, a date, or a string – the collection object will take any data type. If you tried to put a string value in an array that was dimensioned as numeric, it would produce an error message.
- Collections are generally easier to use than arrays. In coding terms, when you create a collection object, it only has two methods (Add and Remove) and two properties (Count and Item), so the object is by no means complicated to program.
- Collections can use keys to locate data. Arrays do not have this function and require looping code to iterate through the array to find specific values.
- The size of an array needs to be defined when it is first created. You need to have an idea of how much data it is going to store. If you need to increase the size of the array you can use ‘ReDim’ to re-size it, but you need to use the keyword ‘Preserve’ if you do not want to lose the data already held in the array. A collection size does not need to be defined. It just grows and shrinks automatically as items are added or removed.
Scope of a Collection Object
In terms of scope, the collection object is only available whilst the workbook is open. It does not get saved when the workbook is saved. If the workbook is re-opened then the collection needs to be re-created using VBA code.
If you want your collection to be available to all the code in your code module, then you need to declare the collection object in the Declare section at the top of the module window.
This will ensure that all your code within that module can access the collection. If you want any module within your workbook to access the collection, then define it as a global object.
Create a Collection, Add Items, and Access Items
A simple collection object can be created in VBA using the following code:
The code creates a new object called ‘MyCollection’ and then the following lines of code use the Add method to add in 3 new values.
Loop Through Collection
You can then use code to iterate through each item in your collection:
Or this code will get the size of the collection with .Count and loop through each index number:
The first For Each Loop is faster than the second For Next loop but it only works in one direction (low index to high). The For Next Loop has the advantage that you can use a different direction (high index to low) and you can also use the Step method to change the increment. This is useful when you want to delete several items since you will need to run the deletion from the end of the collection to the start as the index will change as the deletions take place.
Add Item to Collection
The Add method in a collection has 3 optional parameters – Key, Before, and After.
You can use the ‘Before’ and ‘After’ parameters to define the position of your new item relative to the others already in the collection.
This is done by specifying the index number that you want your new item to be relative to.
In this example ‘Item2’ has been specified to be added before the first indexed item in the collection (which is ‘Item1’). When you iterate through this collection ‘Item2’ will appear first of all, followed by ‘Item1’ and ‘Item3’.
When you specify a ‘Before’ or ‘After’ parameter, the index value is automatically adjusted within the collection so that ‘Item2’ becomes index value of 1 and ‘Item1’ gets moved to an index value of 2.
You can also use the ‘Key’ parameter to add a reference value that you can use to identify the collection item. Note that a key value must be a string and must be unique within the collection.
‘Item2’ has been given a ‘Key’ value of ‘MyKey’ so that you can refer to that item using the value of ‘MyKey’ instead of the index number (2).
Note that the ‘Key’ value has to be a string value. It cannot be any other data type. Note that the collection is Read Only, and you cannot update the key value once it has been set. Also, you cannot check if a key value exists for a specific item in the collection or view the key value which is a bit of a drawback.
The ‘Key’ parameter has the added advantage of making your code more readable, especially if it is being handed over to a colleague to support, and you do not have to iterate through the entire collection to find that value. Imagine if you had a collection of 10,000 items how difficult it would be to reference one specific item!
VBA Coding Made Easy
Stop searching for VBA code online. Learn more about AutoMacro — A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!
Remove an Item from Collection
You can use the ‘Remove’ method to delete items from your collection.
Unfortunately, it is not easy if the collection has a large number of items to work out the index of the item that you want to delete. This is where the ‘Key’ parameter comes in handy when the collection is being created.
When an item is removed from a collection the index values are automatically reset all the way through the collection. This is where the ‘Key’ parameter is so useful when you are deleting several items at once. For example, you could delete item index 105, and instantly item index 106 becomes index 105, and everything above this item has its index value moved down. If you use the Key parameter, there is no need to worry about which index value needs to be removed.
To delete all the collection items and create a new collection, you use the Dim statement again which creates an empty collection.
To remove the actual collection object completely, you can set the object to nothing.
This is useful if the collection is no longer required by your code. Setting the collection object to nothing removes all reference to it and releases the memory that it was using. This can have important implications on speed of execution of your code, if a large object is sitting in memory that is no longer required.
Count the Number of Items in a Collection
You can easily find out the number of items in your collection by using the ‘Count’ property.
You would use this property if you were using a For Next Loop to iterate through the collection as it will provide you with the upper limit for the index number.
Test Collection for a Specific Value
You can iterate through a collection to search for a specific value for an item using a For Each Loop.
The code creates a small collection, and then iterates through it looking for an item called ‘item2”. If found it displays a message box that it has found the specific item.
One of the drawbacks with this methodology is that you cannot access the index value or the key value.
If you use a For Next Loop instead, you can use the For Next counter to get the index value, although you still cannot get the ‘Key’ value.
The For Next counter (n) will provide the index position.
Sort Collection
There is no built-in functionality to sort a collection, but using some ‘out of the box’ thinking, code can be written to do a sort, utilizing Excel’s worksheet sorting function. This code uses a blank worksheet called ‘SortSheet’ to do the actual sorting.
This code first creates a collection with the items added in a random order. It then copies them into the first column on a worksheet (SortSheet).
The code then uses the Excel sort tool to sort the data in the column into ascending order. The code could also be modified to sort into descending order.
The collection is then emptied of data using a For Next Loop. Note that the step option is used so that it clears from the end of the collection to the start. This is because as it clears, the index values are reset, if it cleared from the start, it would not clear correctly (index 2 would become index 1)
Finally, using another For Next Loop, the item values are transferred back into the empty collection
A further For Each Loop proves out that the collection is now in good ascending order.
Unfortunately, this does not deal with any Key values that may have been entered originally, since the Key values cannot be read
Pass a Collection to a Sub / Function
A collection can be passed to a Sub or a Function in the same way as any other parameter
It is important to pass the collection using ‘ByRef’. This means that the original collection is used. If the collection is passed using ‘ByVal’ then this creates a copy of the collection which can have unfortunate repercussions.
If a copy is created using ‘ByVal’ then anything that changes the collection within the function only happens on the copy and not on the original. For example, if within the function, a new item is added to the collection, this will not appear in the original collection, which will create a bug in your code.
Return a Collection from a Function
You can return a collection from a function in the same way as returning any object. You must use the Set keyword.
This code creates a sub routine which creates an object called ‘MyCollection’ and then uses the ‘Set’ keyword to effectively call the function to populate that collection. Once this is done then it displays a message box to show the count of 2 items.
The function PopulateCollection creates a new collection object and populates it with 2 items. It then passes this object back to the collection object created in the original sub routine.
Convert a Collection to an Array
You may wish to convert your collection into an array. You may want to store the data where it can be changed and manipulated. This code creates a small collection and then transfers it into an array
Notice that the collection index starts at 1 whereas the array index starts at 0. Whereas the collection has 3 items, the array only needs to be dimensioned to 2 because there is an element 0
Convert an Array into a Collection
You may want to convert an array into a collection. For example, you may wish to access the data in a faster and more elegant manner that using code to get an array element.
Bear in mind that this will only work for a single dimension of the array because the collection has only one dimension.
If you did wish to use a multi-dimensional array, you could concatenate the array values together for each row within the array using a delimiter character between the array dimensions, so that when reading the collection value, you could programmatically use the delimiter character to separate the values out.
You could also move the data into the collection on the basis that the first-dimension value is added (index 1), and then the next dimension value is added (index 2) and so on.
If the array had, say, 4 dimensions, every fourth value in the collection would be a new set of values.
You could also add array values to use as keys (providing that they are unique) which would add an easy way of locating specific data.
VBA Code Examples Add-in
Easily access all of the code examples found on our site.
Simply navigate to the menu, click, and the code will be inserted directly into your module. .xlam add-in.
Источник
@CharlesWilliams answer is correct: looping through all the values of an array is faster than iterating a Collection or dictionary: so much so, that I always use the Keys() or Items() method of a dictionary when I need to do that — both methods return a vector array.
A note: I use the Dictionary class far more than I use collections, the Exists() method is just too useful.
There are, or course, drawbacks to collections and dictionaries. One of them is that arrays can be 2- or even 3-Dimensional — a much better data structure for tabulated data. You can store arrays as members of a collection, but there’s some downsides to that: one of them is that you might not be getting a reference to the item — unless you use arrItem = MyDictionary(strKey)
you will almost certainly get a ‘ByVal’ copy of the array; that’s bad if your data is dynamic, and subject to change by multiple processes. It’s also slow: lots of allocation and deallocation.
Worst of all, I don’t quite trust VBA to deallocate the memory if I have a collection or dictionary with arrays (or objects!) as members: not on out-of-scope, not by Set objCollection = Nothing
, not even by objDictionary.RemoveAll — it’s difficult to prove that the problem exists with the limited testing toolkit available in the VBE, but I’ve seen enough memory leaks in applications that used arrays in dictionaries to know that you need to be cautious. That being said, I never use an array without an Erase command somewhere.
@JMax has explained the other big plus for arrays: you can populate an array in a single ‘hit’ to the worksheet, and write back your work in a single ‘hit.
You can, of course, get the best of both worlds by constructing an Indexed Array class: a 2-dimensional array with associated collection or dictionary objects storing some kind of row identifier as the keys, and the row ordinals as the data items.
There are no control arrays in VBA like there are in VB. For certain controls you can create a custom class to handle the events. For example, assume you have a userform with two command buttons. In the userform module, put this code
Private mcolEventButtons As Collection
Private Sub UserForm_Initialize()
Dim clsEventButton As CEventButton
Set mcolEventButtons = New Collection
Set clsEventButton = New CEventButton
Set clsEventButton.EventButton = Me.CommandButton1
clsEventButton.RangeAddress = "A1"
mcolEventButtons.Add clsEventButton, Me.CommandButton1.Name
Set clsEventButton = New CEventButton
Set clsEventButton.EventButton = Me.CommandButton2
clsEventButton.RangeAddress = "A10"
mcolEventButtons.Add clsEventButton, Me.CommandButton2.Name
End Sub
Then create a custom class module named CEventButton and put this code
Private WithEvents mctlEventButton As MSForms.CommandButton
Private msRangeAddress As String
Public Property Set EventButton(ctlButton As MSForms.CommandButton)
Set mctlEventButton = ctlButton
End Property
Public Property Get EventButton() As MSForms.CommandButton
Set EventButton = mctlEventButton
End Property
Private Sub mctlEventButton_Click()
Sheet1.Range(Me.RangeAddress).Value = "Something"
End Sub
Public Property Get RangeAddress() As String
RangeAddress = msRangeAddress
End Property
Public Property Let RangeAddress(ByVal sRangeAddress As String)
msRangeAddress = sRangeAddress
End Property
The WithEvents keyword in the variable dimensioning polls the commandbutton’s events and fires just as if it was tied to a particular control and in the userform module.
Here’s what you did: You created a Collection to hold instances of your custom class for as long as the userform is active. This ensures that those instances stay in scope. Then you created a new instance of the class, assigned a particular button to it, and saved it in the collection. You did the same for the next button. In this example there are only two buttons, but if you had more you could continue doing this until you run out of memory.
I create a RangeAddress property in the custom class module as an example. What information you’ll need to store will depend on what you’re ultimately trying to accomplish.
For this example to work, you need to set the ShowModal property of the userform to FALSE, have to commandbuttons named CommandButton1 and CommandButton2, have a sheet with a codename of Sheet1, and probably some other stuff.
In this Article
- What is a Collection in VBA?
- Collections Versus Arrays
- Scope of a Collection Object
- Create a Collection, Add Items, and Access Items
- Loop Through Collection
- Add Item to Collection
- Remove an Item from Collection
- Count the Number of Items in a Collection
- Test Collection for a Specific Value
- Pass a Collection to a Sub / Function
- Return a Collection from a Function
- Convert a Collection to an Array
- Convert an Array into a Collection
This tutorial will demonstrate how to use collections in VBA.
What is a Collection in VBA?
A collection is an object that holds a number of similar items that can easily be accessed and manipulated, even if there are a large number of items within the collection.
You can create your own collections, but VBA also comes with built in collections such as the Sheets Collection, which stores every sheet in the workbook. By using a For Each loop, you can iterate through each worksheet in the Sheets Collection.
Sub TestWorksheets()
Dim Sh As Worksheet
For Each Sh In Sheets
MsgBox Sh.Name
MsgBox Sh.Visible
Next Sh
End Sub
You can also address a specific worksheet in the collection using the index value (it’s position in the collection), or the actual name of the worksheet:
MsgBox Sheets(1).Name
MsgBox Sheets("Sheet1").Name
As worksheets are added or deleted so the Sheets collection grows or shrinks in size.
Note that with VBA collections the index number begins with 1 not with 0.
Collections Versus Arrays
Arrays and Collections can both store data, however they have several notable differences:
- Arrays are multidimensional whereas collections are only single dimension. You can dimension an array with several dimensions e.g.
Dim MyArray(10, 2) As String
This creates an array of 10 rows with 2 columns, almost like a worksheet. A collection is effectively a single column.
- When you populate your array, you need a separate line of code to put a value into each element of the array. If you had a two-dimensional array you would actually need 2 lines of code – one line to address the first column and one line to address the second column. With the Collection object, you simply use the Add method so that the new item is just added into the collection and the index value is automatically adjusted to suit.
- If you need to delete an item of data then it is more complicated in the array. You can set the values of an element to a blank value, but the element itself still exists within the array. If you are using a For Next loop to iterate through the array, the loop will return a blank value, which will need coding to make sure that the blank value is ignored. In a collection you use the Add or Remove methods, and all the indexing and re-sizing is automatically taken care of. The item that has been removed disappears completely. Arrays are useful for a fixed size of data, but collections are better for where the quantity of data is liable to change.
- Collections are Read Only whereas array values can be changed using VBA. With a collection, you would have to remove the value to be changed first and then add in the new changed value.
- In an array, you can only use a single data type for the elements which is set when you dimension the array. However, in the array you can use custom data types that you have designed yourself. You could have a very complicated array structure using a custom data type which in turn has several custom data types below it. In a collection, you can add use data types of data for each item. You could have a numeric value, a date, or a string – the collection object will take any data type. If you tried to put a string value in an array that was dimensioned as numeric, it would produce an error message.
- Collections are generally easier to use than arrays. In coding terms, when you create a collection object, it only has two methods (Add and Remove) and two properties (Count and Item), so the object is by no means complicated to program.
- Collections can use keys to locate data. Arrays do not have this function and require looping code to iterate through the array to find specific values.
- The size of an array needs to be defined when it is first created. You need to have an idea of how much data it is going to store. If you need to increase the size of the array you can use ‘ReDim’ to re-size it, but you need to use the keyword ‘Preserve’ if you do not want to lose the data already held in the array. A collection size does not need to be defined. It just grows and shrinks automatically as items are added or removed.
Scope of a Collection Object
In terms of scope, the collection object is only available whilst the workbook is open. It does not get saved when the workbook is saved. If the workbook is re-opened then the collection needs to be re-created using VBA code.
If you want your collection to be available to all the code in your code module, then you need to declare the collection object in the Declare section at the top of the module window.
This will ensure that all your code within that module can access the collection. If you want any module within your workbook to access the collection, then define it as a global object.
Global MyCollection As New Collection
Create a Collection, Add Items, and Access Items
A simple collection object can be created in VBA using the following code:
Sub CreateCollection()
'Create Collection
Dim MyCollection As New Collection
'Add Items to Collection
MyCollection.Add "Item1"
MyCollection.Add "Item2"
MyCollection.Add "Item3"
End Sub
The code creates a new object called ‘MyCollection’ and then the following lines of code use the Add method to add in 3 new values.
Loop Through Collection
You can then use code to iterate through each item in your collection:
For Each Item In MyCollection
MsgBox Item
Next Item
Or this code will get the size of the collection with .Count and loop through each index number:
For n = 1 To MyCollection.Count
MsgBox MyCollection(n)
Next n
The first For Each Loop is faster than the second For Next loop but it only works in one direction (low index to high). The For Next Loop has the advantage that you can use a different direction (high index to low) and you can also use the Step method to change the increment. This is useful when you want to delete several items since you will need to run the deletion from the end of the collection to the start as the index will change as the deletions take place.
Add Item to Collection
The Add method in a collection has 3 optional parameters – Key, Before, and After.
You can use the ‘Before’ and ‘After’ parameters to define the position of your new item relative to the others already in the collection.
This is done by specifying the index number that you want your new item to be relative to.
Sub CreateCollection()
Dim MyCollection As New Collection
MyCollection.Add "Item1"
MyCollection.Add "Item2", , 1
MyCollection.Add "Item3"
End Sub
In this example ‘Item2’ has been specified to be added before the first indexed item in the collection (which is ‘Item1’). When you iterate through this collection ‘Item2’ will appear first of all, followed by ‘Item1’ and ‘Item3’.
When you specify a ‘Before’ or ‘After’ parameter, the index value is automatically adjusted within the collection so that ‘Item2’ becomes index value of 1 and ‘Item1’ gets moved to an index value of 2.
You can also use the ‘Key’ parameter to add a reference value that you can use to identify the collection item. Note that a key value must be a string and must be unique within the collection.
Sub CreateCollection()
Dim MyCollection As New Collection
MyCollection.Add "Item1"
MyCollection.Add "Item2", "MyKey"
MyCollection.Add "Item3"
MsgBox MyCollection("MyKey")
End Sub
‘Item2’ has been given a ‘Key’ value of ‘MyKey’ so that you can refer to that item using the value of ‘MyKey’ instead of the index number (2).
Note that the ‘Key’ value has to be a string value. It cannot be any other data type. Note that the collection is Read Only, and you cannot update the key value once it has been set. Also, you cannot check if a key value exists for a specific item in the collection or view the key value which is a bit of a drawback.
The ‘Key’ parameter has the added advantage of making your code more readable, especially if it is being handed over to a colleague to support, and you do not have to iterate through the entire collection to find that value. Imagine if you had a collection of 10,000 items how difficult it would be to reference one specific item!
VBA Coding Made Easy
Stop searching for VBA code online. Learn more about AutoMacro — A VBA Code Builder that allows beginners to code procedures from scratch with minimal coding knowledge and with many time-saving features for all users!
Learn More
Remove an Item from Collection
You can use the ‘Remove’ method to delete items from your collection.
MyCollection.Remove (2)
Unfortunately, it is not easy if the collection has a large number of items to work out the index of the item that you want to delete. This is where the ‘Key’ parameter comes in handy when the collection is being created.
MyCollection.Remove (“MyKey”)
When an item is removed from a collection the index values are automatically reset all the way through the collection. This is where the ‘Key’ parameter is so useful when you are deleting several items at once. For example, you could delete item index 105, and instantly item index 106 becomes index 105, and everything above this item has its index value moved down. If you use the Key parameter, there is no need to worry about which index value needs to be removed.
To delete all the collection items and create a new collection, you use the Dim statement again which creates an empty collection.
Dim MyCollection As New Collection
To remove the actual collection object completely, you can set the object to nothing.
Set MyCollection = Nothing
This is useful if the collection is no longer required by your code. Setting the collection object to nothing removes all reference to it and releases the memory that it was using. This can have important implications on speed of execution of your code, if a large object is sitting in memory that is no longer required.
Count the Number of Items in a Collection
You can easily find out the number of items in your collection by using the ‘Count’ property.
MsgBox MyCollection.Count
You would use this property if you were using a For Next Loop to iterate through the collection as it will provide you with the upper limit for the index number.
Test Collection for a Specific Value
You can iterate through a collection to search for a specific value for an item using a For Each Loop.
Sub SearchCollection()
Dim MyCollection as New Collection
MyCollection.Add "Item1"
MyCollection.Add "Item2"
MyCollection.Add "Item3"
For Each Item In MyCollection
If Item = "Item2" Then
MsgBox Item & " Found"
End If
Next
End Sub
The code creates a small collection, and then iterates through it looking for an item called ‘item2”. If found it displays a message box that it has found the specific item.
One of the drawbacks with this methodology is that you cannot access the index value or the key value.
If you use a For Next Loop instead, you can use the For Next counter to get the index value, although you still cannot get the ‘Key’ value.
Sub SearchCollection()
Dim MyCollection As New Collection
MyCollection.Add "Item1"
MyCollection.Add "Item2"
MyCollection.Add "Item3"
For n = 1 To MyCollection.Count
If MyCollection.Item(n) = "Item2" Then
MsgBox MyCollection.Item(n) & " found at index position " & n
End If
Next n
End Sub
The For Next counter (n) will provide the index position.
Sort Collection
There is no built-in functionality to sort a collection, but using some ‘out of the box’ thinking, code can be written to do a sort, utilizing Excel’s worksheet sorting function. This code uses a blank worksheet called ‘SortSheet’ to do the actual sorting.
Sub SortCollection()
Dim MyCollection As New Collection
Dim Counter As Long
'Build collection with random order items
MyCollection.Add "Item5"
MyCollection.Add "Item2"
MyCollection.Add "Item4"
MyCollection.Add "Item1"
MyCollection.Add "Item3"
'Capture number of items in collection for future use
Counter = MyCollection.Count
'Iterate through the collection copying each item to a consecutive cell on ‘SortSheet’ (column A)
For n = 1 To MyCollection.Count
Sheets("SortSheet").Cells(n, 1) = MyCollection(n)
Next n
'Activate the sortsheet and use the Excel sort routine to sort the data into ascending order
Sheets("SortSheet").Activate
Range("A1:A" & MyCollection.Count).Select
ActiveWorkbook.Worksheets("SortSheet").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("SortSheet"). Sort.SortFields.Add2 Key:=Range( _
"A1:A5"), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:= _
xlSortNormal
With ActiveWorkbook.Worksheets("SortSheet").Sort
.SetRange Range("A1:A5")
.Header = xlGuess
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
'Delete all the items in the collection – note that this For Next Loop runs in reverse order
For n = MyCollection.Count To 1 Step -1
MyCollection.Remove (n)
Next n
'Copy the cell values back into the empty collection object using the stored value (Counter) for the ‘loop
For n = 1 To Counter
MyCollection.Add Sheets("SortSheet").Cells(n, 1).Value
Next n
'Iterate through the collection to prove out the order that the items are now in
For Each Item In MyCollection
MsgBox Item
Next Item
'Clear the worksheet (sortsheet) – if necessary, delete it as well
Sheets("SortSheet").Range(Cells(1, 1), Cells(Counter, 1)).Clear
End Sub
This code first creates a collection with the items added in a random order. It then copies them into the first column on a worksheet (SortSheet).
The code then uses the Excel sort tool to sort the data in the column into ascending order. The code could also be modified to sort into descending order.
The collection is then emptied of data using a For Next Loop. Note that the step option is used so that it clears from the end of the collection to the start. This is because as it clears, the index values are reset, if it cleared from the start, it would not clear correctly (index 2 would become index 1)
Finally, using another For Next Loop, the item values are transferred back into the empty collection
A further For Each Loop proves out that the collection is now in good ascending order.
Unfortunately, this does not deal with any Key values that may have been entered originally, since the Key values cannot be read
VBA Programming | Code Generator does work for you!
Pass a Collection to a Sub / Function
A collection can be passed to a Sub or a Function in the same way as any other parameter
Function MyFunction(ByRef MyCollection as Collection)
It is important to pass the collection using ‘ByRef’. This means that the original collection is used. If the collection is passed using ‘ByVal’ then this creates a copy of the collection which can have unfortunate repercussions.
If a copy is created using ‘ByVal’ then anything that changes the collection within the function only happens on the copy and not on the original. For example, if within the function, a new item is added to the collection, this will not appear in the original collection, which will create a bug in your code.
Return a Collection from a Function
You can return a collection from a function in the same way as returning any object. You must use the Set keyword.
Sub ReturnFromFunction()
Dim MyCollection As Collection
Set MyCollection = PopulateCollection
MsgBox MyCollection.Count
End Sub
This code creates a sub routine which creates an object called ‘MyCollection’ and then uses the ‘Set’ keyword to effectively call the function to populate that collection. Once this is done then it displays a message box to show the count of 2 items.
Function PopulateCollection() As Collection
Dim MyCollection As New Collection
MyCollection.Add "Item1"
MyCollection.Add "Item2"
Set PopulateCollection = MyCollection
End Function
The function PopulateCollection creates a new collection object and populates it with 2 items. It then passes this object back to the collection object created in the original sub routine.
Convert a Collection to an Array
You may wish to convert your collection into an array. You may want to store the data where it can be changed and manipulated. This code creates a small collection and then transfers it into an array
Notice that the collection index starts at 1 whereas the array index starts at 0. Whereas the collection has 3 items, the array only needs to be dimensioned to 2 because there is an element 0
Sub ConvertCollectionToArray()
Dim MyCollection As New Collection
Dim MyArray(2) As String
MyCollection.Add "Item1"
MyCollection.Add "Item2"
MyCollection.Add "Item3"
For n = 1 To MyCollection.Count
MyArray(n - 1) = MyCollection(n)
Next n
For n = 0 To 2
MsgBox MyArray(n)
Next n
End Sub
Convert an Array into a Collection
You may want to convert an array into a collection. For example, you may wish to access the data in a faster and more elegant manner that using code to get an array element.
Bear in mind that this will only work for a single dimension of the array because the collection has only one dimension.
Sub ConvertArrayIntoCollection()
Dim MyCollection As New Collection
Dim MyArray(2) As String
MyArray(0) = "item1"
MyArray(1) = "Item2"
MyArray(2) = "Item3"
For n = 0 To 2
MyCollection.Add MyArray(n)
Next n
For Each Item In MyCollection
MsgBox Item
Next Item
End Sub
If you did wish to use a multi-dimensional array, you could concatenate the array values together for each row within the array using a delimiter character between the array dimensions, so that when reading the collection value, you could programmatically use the delimiter character to separate the values out.
You could also move the data into the collection on the basis that the first-dimension value is added (index 1), and then the next dimension value is added (index 2) and so on.
If the array had, say, 4 dimensions, every fourth value in the collection would be a new set of values.
You could also add array values to use as keys (providing that they are unique) which would add an easy way of locating specific data.
На чтение 24 мин. Просмотров 33.7k.
Леонард Лаудер
Я не строитель зданий, я строитель коллекций
Содержание
- Краткое руководство по коллекциям
- Введение
- Что такое коллекция?
- Коллекции против Массивов
- Как создать коллекцию
- Удаление всех элементов из коллекции
- Добавление предметов в коллекцию
- Доступ к элементам коллекции
- Добавление разных типов
- Добавление элементов с помощью ключа
- Доступ ко всем элементам в коллекции
- Сортировка коллекции
- Использование коллекций с функциями и подпрограммами
- Заключение
Краткое руководство по коллекциям
Задача | Пример |
Объявить | Dim coll As Collection |
Создать во время выполнения | Set coll = New Collection |
Объявить и создать | Dim coll As New Collection |
Добавить элемент | coll.Add «Яблоко» |
Доступ к элементу | coll(1) or coll(2) |
Элемент доступа добавлен в первый раз |
coll(1) |
Доступ к элементу добавлен в последний раз |
coll(coll.Count) |
Получить количество предметов | coll.Count |
Доступ ко всем предметам | Dim i As Long For i = 1 To coll.Count Debug.Print coll(i) Next i |
Доступ ко всем предметам (For Each) |
Dim fruit As Variant For Each fruit In coll Debug.Print fruit Next fruit |
Удалить элемент | coll.Remove(1) |
Удалить все элементы | Set coll = New Collection |
Введение
Коллекции являются очень важной частью VBA. Если вы пользовались VBA какое-то время, вы будете использовать Коллекции. Наиболее распространенными из них являются
Workbooks, Worksheets, коллекции Range и Cells.
В следующем коде показаны некоторые примеры использования коллекции Workbooks VBA.
' Workbooks это коллекция всех открытых рабочих книг ' Count - это количество книг в коллекции. Debug.Print Workbooks.Count ' Напечатайте полное имя книги с именем Пример.xlsm Debug.Print Workbooks("Пример.xlsm").FullName ' Напечатайте полное название книги, которая была открыта второй Debug.Print Workbooks(2).FullName
Коллекции похожи на массивы, поэтому важно понимать, что они из себя представляют и чем они отличаются от массивов.
Что такое коллекция?
Коллекции и массивы используются для группировки переменных. Они оба хранят набор похожих предметов, например список студенческих оценок или названий стран. Использование коллекции или массива позволяет быстро и легко манипулировать большим количеством предметов.
В своей статье о массивах я объяснил простым языком, что такое массивы и почему они так полезны. Я кратко изложу эту информацию здесь.
Если вы сохраняете оценки одного ученика, вы можете легко сделать это, используя одну переменную.
Dim mark As Long mark = sheetMarks.Range("A1")
Однако в большинстве случаев вам придется иметь дело с несколькими студентами. Представьте, что вы хотите хранить оценки 100 учеников. Если вы не использовали коллекции или массивы, вам нужно было бы создать сотню переменных — одну переменную для хранения оценки для каждого учащегося.
Другая проблема заключается в том, что вы должны использовать эти переменные по отдельности. Если вы хотите сохранить 100 отметок, вам понадобится строка кода каждый раз, когда вы хотите сохранить значение в переменной.
' Объявите переменную для каждой оценки Dim mark1 As Long Dim mark2 As Long . . . Dim mark100 As Long ' Сохраните отметки на листе в переменной mark1 = sheetMarks.Range("A1") mark2 = sheetMarks.Range("A2") . . . mark100 = sheetMarks.Range("A100")
Как вы можете видеть в приведенном выше примере, написание такого кода означало бы сотни строк повторяющегося кода. Когда вы используете коллекцию или массив, вам нужно только объявить одну переменную. Использование цикла с коллекцией или массивами означает, что вам нужна только одна строка для добавления или чтения значений.
Если мы переписываем приведенный выше пример с использованием коллекции, нам нужно всего несколько строк кода
' Создать коллекцию Dim collMarks As New Collection ' Прочитайте 100 значений в коллекцию Dim c As Range For Each c In Sheet1.Range("A1:A100") ' Эта строка используется для добавления всех значений collMarks.Add c.Value Next
Коллекции против Массивов
Мы рассмотрели, что общего у коллекций и массивов. Так в чем же разница и зачем использовать один вместо другого?
Основное отличие состоит в том, что с массивом вы обычно устанавливаете размер один раз. Это означает, что вы знаете размер до того, как начнете добавлять элементы. Позвольте мне объяснить это на примере.
Пример: когда Массив лучше
Представьте, что у вас есть лист оценок учеников с одним учеником на строку:
Вы хотите хранить информацию о каждом ученике. В этом примере вы можете легко посчитать количество строк, чтобы получить количество студентов. Другими словами, вы знаете количество предметов заранее.
' Получить последнюю строку - это количество студентов Dim lStudentCount As Long lStudentCount = Sheet1.Range("A" & Rows.Count).End(xlUp).Row ' Создать массив правильного размера Dim arr() As Long ReDim arr(1 To lStudentCount)
В примере кода, как видите, мы получаем количество студентов путем подсчета строк. Затем мы можем использовать это для создания массива правильного размера.
Массивы используются, когда размер фиксирован.
Давайте теперь посмотрим на второй пример, где мы не знаем количество предметов заранее.
Пример: когда Коллекция лучше
В этом примере у нас есть один и тот же рабочий лист студента, но на этот раз нам нужны только студенты с заданными критериями. Например, только студенты из Твери или Москвы, которые изучают математику или историю. Другими словами, вы не будете знать, как выбрать ученика, пока не прочитаете его данные на рабочем листе.
Представьте также, что студенты могут быть добавлены или удалены из списка во время работы приложения.
Таким образом, в этом примере количество студентов не является фиксированным и сильно меняется. Здесь вы не знаете количество студентов заранее. Поэтому вы не знаете, какой размер массива создать.
Вы можете создать массив максимально возможного размера. Проблема в том, что у вас будет много пустых слотов, и вам придется добавить код, чтобы справиться с ними. Если вы прочитаете 50 учеников с максимумом 1000, то у вас будет 950 неиспользуемых слотов массива.
Вы также можете изменить размер массива для каждого элемента по мере его добавления. Это очень неэффективно и довольно грязно.
Так что для этого примера лучше использовать коллекцию.
' Объявить Dim coll As New Collection ' Добавить элемент - VBA следит за изменением размера coll.Add "Яблоко" coll.Add "Слива" ' удалить элемент - VBA следит за изменением размера coll.Remove 1
Когда вы добавляете или удаляете элемент в коллекцию, VBA выполняет все изменения размера за вас. Вам не нужно указывать размер или выделять новые пробелы. VBA делает это самостоятельно. Все, что вам нужно сделать, это добавить элемент или удалить его.
Коллекция используется, когда размер часто изменяется.
Еще одно преимущество коллекций
Коллекции гораздо проще использовать, чем массивы, особенно если вы новичок в программировании. Большую часть времени вы делаете три вещи с коллекциями:
- Создать коллекцию
- Добавьте несколько предметов
- Прочитайте предмет
Так что, если вы не имеете дело с большим количеством предметов, тогда использование Коллекции может быть намного удобнее в использовании.
Недостаток коллекций
Основные типы данных (т.е. переменные, такие как string, date, long, currency и т.д.) в коллекциях доступны только для чтения. Вы можете добавить или удалить элемент, но не можете изменить его значение. Если вы собираетесь изменять значения в группе элементов, вам нужно будет использовать массив.
Если вы храните объект в коллекции, вы можете изменить значение, так как коллекция хранит ссылку, а не фактический объект.
Коллекция только для чтения
Теперь, когда мы знаем, когда и зачем использовать коллекцию, давайте посмотрим, как ее использовать.
Как создать коллекцию
Вы можете объявить и создать в одной строке, как это делает следующий код:
' Объявить и создать Dim coll As New Collection
Как видите, вам не нужно указывать размер. После того, как ваша коллекция создана, вы можете легко добавлять в нее элементы.
Вы также можете объявить и затем создать коллекцию, если и когда вам это нужно.
' Объявить Dim coll As Collection ' Создать Коллекцию Set coll = New Collection
Незначительная разница между этими методами
Разница между этими методами заключается в том, что для первого всегда создается коллекция. Для второго метода коллекция создается только при достижении строки Set. Таким образом, вы можете установить код для создания коллекции только при соблюдении определенного условия.
' Объявить Dim coll As Collection ' Создать коллекцию, если файл найден If filefound = True Then Set coll = New Collection Endif
Преимущество использования этого метода минимально. Выделение памяти было важно еще в 1990-х годах, когда память компьютера была ограничена. Если вы не создаете огромное количество коллекций на медленном ПК, вы никогда не заметите никакой выгоды.
Использование Set означает, что коллекция будет вести себя иначе, чем когда вы устанавливаете коллекцию в ничто. Следующий раздел объясняет это.
Удаление всех элементов из коллекции
Коллекция не имеет функции RemoveAll. Однако, чтобы удалить все элементы из коллекции, вы можете просто установить ее в новую коллекцию.
Set Coll = New Collection.
VBA удалит коллекцию, потому что мы больше не ссылаемся на нее. Когда мы удаляем все предметы, мы обычно хотим использовать коллекцию снова, поэтому мы эффективно убиваем двух зайцев одним выстрелом, используя этот метод.
Sub UdalitKollekciyu() Dim coll1 As New Collection coll1.Add "яблоко" coll1.Add "слива" ' Оригинальная коллекция удалена Set coll1 = New Collection End Sub
Следует помнить одну тонкую вещь: если у нас есть две или более переменных, которые ссылаются на одну и ту же коллекцию, она не будет удалена (см. Очистка памяти в VBA).
В приведенном ниже примере исходные элементы коллекции не удаляются, так как он все еще является ссылкой по coll2.
Sub KollekciyaNeUdalyaetsya() Dim coll1 As New Collection, coll2 As Collection coll1.Add "яблоко" coll1.Add "слива" ' Coll1 и Coll2 оба ссылаются на коллекцию Set coll2 = coll1 ' Coll1 теперь ссылается на новую коллекцию Set coll1 = New Collection ' Coll2 относится к оригинальной коллекции - печатает яблоко Debug.Print coll2(1) End Sub
Добавление предметов в коллекцию
Добавить предметы в коллекцию просто. Вы используете свойство add, за которым следует значение, которое вы хотите добавить.
collFruit.Add "Яблоко" collFruit.Add "Слива"
Вы можете иметь любой базовый тип в коллекции, например, Double
collTotals.Add 45.67 collTotals.Add 34.67
Когда вы добавляете элементы таким способом, они добавляются в следующий доступный индекс. В примере с фруктами яблоко добавляется в положение 1, а слива — в положение 2.
Before и After
Вы можете использовать параметры «Before» или «After», чтобы указать, где вы хотите разместить элемент в коллекции. Обратите внимание, что вы не можете использовать оба этих аргумента одновременно.
collFruit.Add "Яблоко" collFruit.Add "Слива" ' Добавить лимон перед первым пунктом collFruit.Add "Лимон", Before:=1
После этого кода порядок коллекции выглядит так:
- Лимон
- Яблоко
- Слива
collFruit.Add "Яблоко" collFruit.Add "Слива" ' Добавьте лимон после первого пункта collFruit.Add "Лимон", After:=1
После этого кода порядок коллекции выглядит так:
- Яблоко
- Лимон
- Слива
Доступ к элементам коллекции
Для доступа к элементам коллекции вы просто используете индекс. Как мы увидели, индекс — это позиция элемента в коллекции на основе порядка, в котором они были добавлены.
Порядок также можно установить с помощью параметра «Before» или «After».
Sub dostup() Dim coll As New Collection coll.Add "Яблоко" coll.Add "Слива" ' Будет напечатано Яблоко Debug.Print coll(1) ' добавьте апельсин в начало coll.Add "Апельсин", Before:=1 ' будет напечатан Апельсин Debug.Print coll(1) ' Будет печатать Яблоко, так как оно сейчас в положении 2 Debug.Print coll(2) End Sub
Вы также можете использовать свойство элемента для доступа к элементу в коллекции. Это метод по умолчанию для коллекции, поэтому следующие строки кода эквивалентны.
Debug.Print coll(1) Debug.Print coll.Item(1)
Элементы в коллекции доступны только для чтения?
Это очень важный момент. Когда базовый тип данных хранится в коллекции, он доступен только для чтения. Базовый тип данных — это строка, дата, целое число, длина и т.д.
Если вы попытаетесь обновить элемент коллекции, вы получите сообщение об ошибке. Следующий код выдает ошибку «Требуется объект».
Sub NapisatZnachenie() Dim coll As New Collection coll.Add "Яблоко" ' Эта строка вызывает ОШИБКУ coll(1) = "Слива" End Sub
Вы можете изменить объект, который хранится в коллекции
Sub IzmenitObekt() Dim coll As New Collection Dim o As New Class1 ' Добавить объект в коллекцию o.fruit = "Яблоко" coll.Add o ' Изменить фруктовую часть Class1 coll(1).fruit = "Слива" ' Печатает Слива Debug.Print coll(1).fruit End Sub
Это может показаться противоречивым поведением, но тому есть веская причина. Любой элемент, добавленный в коллекцию, доступен только для чтения. Однако при добавлении объекта в коллекцию объект не добавляется как элемент. Переменная с адресом памяти объекта добавляется в качестве элемента.
Это происходит незаметно, чтобы вы этого не заметили. Переменная item на самом деле доступна только для чтения, но объект, на который она указывает, — нет.
Все, что вам нужно помнить, это то, что базовые типы данных в коллекции доступны только для чтения. Объекты в коллекции могут быть изменены.
Вы можете прочитать больше об объектах в памяти здесь.
Добавление разных типов
Вы также можете добавлять различные типы предметов в коллекцию.
collFruit.Add "Яблоко" collFruit.Add 45 collFruit.Add #12/12/2019#
Это редко нужно. В VBA коллекции Sheets содержат листы типа Worksheet и типа Chart. (Чтобы создать лист с диаграммой, просто щелкните правой кнопкой мыши любую диаграмму, выберите «Переместить» и установите переключатель «Новый лист»).
Следующий код отображает тип и имя всех листов в текущей книге. Обратите внимание, что для доступа к другому типу необходимо, чтобы переменная For Each была вариантом, иначе вы получите ошибку.
Sub listi() Dim sh As Variant For Each sh In ThisWorkbook.Sheets ' Тип отображения и название листа Debug.Print TypeName(sh), sh.Name Next End Sub
При доступе к различным элементам переменная For Each должна быть вариантом. Если это не так, вы получите ошибку при доступе к другому типу, который вы объявили. Если мы объявим sh в качестве рабочего листа в приведенном выше примере, это приведет к ошибке при попытке доступа к листу типа Chart.
Редко вам понадобится коллекция разных типов, но, как видите, иногда это может быть полезно.
Добавление элементов с помощью ключа
Вы также можете добавить элементы, используя ключ, как показано в следующем примере:
collMark.Add Item:=45, Key:="Петр" Debug.Print "Оценки Петра: ",collMark("Петр")
Я включил имена параметров, чтобы сделать приведенный выше пример понятным. Однако вам не нужно этого делать. Просто помните, что ключ является вторым параметром и должен быть уникальной строкой.
Следующий код показывает второй пример использования ключей.
Sub IspolzovanieKlyuchei() Dim collMark As New Collection collMark.Add 45, "Петр" collMark.Add 67, "Юрий" collMark.Add 12, "Ольга" collMark.Add 89, "Елена" ' Печатать оценку Елены Debug.Print collMark("Елена") ' Печатать оценку Петра Debug.Print collMark("Петр") End Sub
Использование ключей имеет три преимущества:
- Если заказ изменится, ваш код все равно получит доступ к нужному товару
- Вы можете напрямую получить доступ к элементу, не читая всю коллекцию
- Это может сделать ваш код более читабельны
В коллекции Workbooks VBA доступ к рабочей книге гораздо лучше по ключу (имени), чем по индексу. Порядок зависит от порядка, в котором они были открыты, и поэтому является довольно случайным.
Sub IspolzovanieWorkbook() Debug.Print Workbooks("Пример.xlsm").Name Debug.Print Workbooks(1).Name End Sub
Когда использовать ключи
Пример использования ключей: представьте, что у вас есть набор идентификаторов для 10 000 учащихся вместе с их оценками.
У вас также есть несколько отчетов на листе, которые содержат списки идентификаторов студентов. Для каждого из этих рабочих листов вам необходимо распечатать отметку для каждого учащегося.
Вы можете сделать это, добавив 10 000 студентов в коллекцию, используя их идентификатор в качестве ключа. Когда вы читаете удостоверение личности с листа, вы можете получить прямой доступ к оценкам этого студента.
Если вы не используете ключ, вам придется искать по 10 000 идентификаторов для каждого идентификатора в отчете.
Недостаток использования ключей в коллекциях
В коллекциях есть два недостатка ключей
- Вы не можете проверить, существует ли Ключ.
- Вы не можете обновить значение, хранящееся в ключе
Первый вопрос легко обойти. Следующий код проверяет, существует ли ключ.
Function Exists(coll As Collection, key As String) As Boolean On Error Goto EH coll.Item key Exists = True EH: End Function
Вы можете использовать это так:
Sub TestExists() Dim coll As New Collection coll.Add Item:=5, key:="Яблоко" coll.Add Item:=8, key:="Слива" ' Печатает истина Debug.Print Exists(coll, "Яблоко") ' Печатает ложь Debug.Print Exists(coll, "Апельсин") ' Печатает истина Debug.Print Exists(coll, "Слива") End Sub
Второй вопрос не так легко обойти, если у вас нет хороших знаний в программировании.
Если вы хотите использовать ключи, есть альтернатива Коллекции. Вы можете использовать словарь. Словарь предоставляет больше возможностей для работы с клавишами. Вы можете проверить, существуют ли ключи, обновить значения в ключах, получить список ключей и так далее.
Доступ ко всем элементам в коллекции
Для доступа ко всем элементам в коллекции вы можете использовать цикл For или цикл For Each. Давайте рассмотри каждый из них.
Использование цикла For
В обычном цикле For вы используете индекс для доступа к каждому элементу. В следующем примере выводится имя всех открытых рабочих книг.
Sub VseWorkbook() Dim i As Long For i = 1 To Workbooks.Count Debug.Print Workbooks(i).Name Next i End Sub
Вы можете видеть, что мы используем диапазон от 1 до Workbooks.Count. Первый элемент всегда находится в первом положении, а последний элемент всегда находится в положении, указанном свойством Count коллекции.
В следующем примере распечатываются все элементы в пользовательской коллекции.
Sub IspolzovanieKollekcii() ' Объявить и создать коллекцию Dim collFruit As New Collection ' Добавить элементы collFruit.Add "Яблоко" collFruit.Add "Слива" collFruit.Add "Груша" ' Печать всех элементов Dim i As Long For i = 1 To collFruit.Count Debug.Print collFruit(i) Next i End Sub
Использование цикла For Each
Цикл For Each, который является специализированным циклом, используется для коллекций. Он не использует индекс, а формат показан в следующем примере.
Sub VseWorkbookForEach() Dim book As Variant For Each book In Workbooks Debug.Print book.Name Next End Sub
Формат цикла For:
For i = 1 To Coll.Count
Next
где i — long, Coll — коллекция
Формат цикла For Each:
For Each var In Coll
Next
где var — вариант, а Coll — коллекция
Чтобы получить доступ к каждому элементу:
For: Coll(i)
For Each: Var
В следующем примере показаны циклы для приведенного выше примера пользовательской коллекции.
Sub IspolzovanieOboihCiklov() ' Объявить и создать коллекцию Dim collFruit As New Collection ' Добавить элементы collFruit.Add "Яблоко" collFruit.Add "Слива" collFruit.Add "Груша" ' Печать всех элементов, используя For Dim i As Long For i = 1 To collFruit.Count Debug.Print collFruit(i) Next i ' Печать всех элементов, используя For Each Dim fruit As Variant For Each fruit In collFruit Debug.Print fruit Next fruit End Sub
For Each против For
Важно понимать разницу между двумя циклами.
Цикл For Each
- быстрее
- аккуратнее писать
- имеет только один заказ — от низкого индекса до высокого
Цикл For
- медленнее
- не так аккуратен
- можно получить доступ в другом порядке
Давайте сравним циклы по каждому из этих атрибутов
Скорость
For Each считается быстрее, чем цикл For. В настоящее время это проблема, только если у вас большая коллекция и / или медленный компьютер/сеть.
Аккуратнее
Цикл For Each аккуратнее писать, особенно если вы используете вложенные циклы. Сравните следующие циклы. Оба печатают названия всех рабочих листов в открытых рабочих книгах.
Sub PechatatNazvaniyaFor() ' Напечатайте названия рабочих листов из всех открытых рабочих книг Dim i As Long, j As Long For i = 1 To Workbooks.Count For j = 1 To Workbooks(i).Worksheets.Count Debug.Print Workbooks(i).Name, Workbooks(i).Worksheets(j).Name Next j Next i End Sub Sub PechatatNazvaniyaForEach() ' Напечатайте названия рабочих листов из всех открытых рабочих книг Dim bk As Workbook, sh As Worksheet For Each bk In Workbooks For Each sh In bk.Worksheets Debug.Print bk.Name, sh.Name Next sh Next bk End Sub
Цикл For Each гораздо удобнее для написания и менее подвержен ошибкам.
Порядок
Порядок цикла For Each всегда от самого низкого индекса до самого высокого. Если вы хотите получить другой заказ, вам нужно использовать цикл For. Порядок цикла For можно изменить. Вы можете прочитать предметы в обратном порядке. Вы можете прочитать раздел предметов или вы можете прочитать каждый второй элемент.
Sub ChitatSpravaNalevo() ' Просмотрите листы справа налево Dim i As Long For i = ThisWorkbook.Worksheets.Count To 1 Step -1 Debug.Print ThisWorkbook.Worksheets(i).Name Next i ' Пройдите первые 3 листа For i = 1 To 3 Debug.Print ThisWorkbook.Worksheets(i).Name Next i ' Пройдите каждый второй лист For i = 1 To ThisWorkbook.Worksheets.Count Step 2 Debug.Print ThisWorkbook.Worksheets(i).Name Next i End Sub
Цикл For дает больше гибкости, но реальность такова, что большую часть времени базовый порядок — это все, что вам нужно.
Сортировка коллекции
Для коллекции VBA нет встроенной сортировки. Однако мы можем использовать QuickSort.
Sub QuickSort(coll As Collection, first As Long, last As Long) Dim vCentreVal As Variant, vTemp As Variant Dim lTempLow As Long Dim lTempHi As Long lTempLow = first lTempHi = last vCentreVal = coll((first + last) 2) Do While lTempLow <= lTempHi Do While coll(lTempLow) < vCentreVal And lTempLow < last lTempLow = lTempLow + 1 Loop Do While vCentreVal < coll(lTempHi) And lTempHi > first lTempHi = lTempHi - 1 Loop If lTempLow <= lTempHi Then ' Поменять значения vTemp = coll(lTempLow) coll.Add coll(lTempHi), After:=lTempLow coll.Remove lTempLow coll.Add vTemp, Before:=lTempHi coll.Remove lTempHi + 1 ' Перейти к следующим позициям lTempLow = lTempLow + 1 lTempHi = lTempHi - 1 End If Loop If first < lTempHi Then QuickSort coll, first, lTempHi If lTempLow < last Then QuickSort coll, lTempLow, last End Sub
Вы можете использовать это так:
Sub TestSort() Dim coll As New Collection coll.Add "Москва" coll.Add "Тверь" coll.Add "Пенза" coll.Add "Новосибирск" QuickSort coll, 1, coll.Count Dim v As Variant For Each v In coll Debug.Print v Next End Sub
Использование коллекций с функциями и подпрограммами
Использовать коллекцию в качестве параметра или возвращаемого значения очень легко. Мы рассмотрим их по очереди.
Передача Коллекции в Sub / Function
Это просто передать коллекцию в функцию или подпункт. Она передается как любой параметр, как показано в следующем примере кода.
Sub IspolzovatColl() ' Создать коллекцию Dim coll As New Collection ' Добавить элементы coll.Add "Яблоко" coll.Add "Апельсин" ' Перейти на sub PrintColl coll End Sub ' Sub принимает коллекцию в качестве аргумента Sub PrintColl(ByRef coll As Collection) Dim item As Variant For Each item In coll Debug.Print item Next End Sub
Вы можете увидеть, насколько полезен вспомогательный PrintColl в примере. На нем будут напечатаны все элементы ЛЮБОЙ коллекции. Размер или тип элемента не имеет значения. Это показывает, насколько гибкими должны быть коллекции.
Передача ByVal против ByRef
Здесь следует помнить одну тонкую вещь: передача по значению (By Val) и передача по ссылке (ByRef) немного отличаются.
Для простой передачи переменной значение означает, что копия создана. Это означает, что если функция / подчиненный элемент изменится, значение не изменится, когда вы вернетесь к вызывающей процедуре.
В следующем примере мы передаем итоговое значение, используя ByVal и ByRef. Вы увидите, что после того, как мы передаем использование ByRef, значение изменилось в вызывающей процедуре.
Sub TipiPeredachi() Dim total As Long total = 100 PassByValue total ' Печатает 100 Debug.Print total PassByReference total ' Печатает 555 Debug.Print total End Sub Sub PassByValue(ByVal total As Long) ' значение изменилось только в этом sub total = 555 End Sub Sub PassByReference(ByRef total As Long) ' значение также изменилось за пределами этого sub total = 555 End Sub
Использование ByVal и ByRef с коллекцией немного отличается. Если вы добавляете или удаляете элемент, коллекция в исходном вызывающем абоненте также будет изменена. Таким образом, Subs в следующем примере удалят первый элемент из исходной коллекции.
Sub UdalitByRef(ByRef coll As Collection) coll.Remove 1 End Sub Sub RemoveByVal(ByVal coll As Collection) coll.Remove 1 End Sub
Причина этого заключается в том, что переменная Collection содержит указатель. Это означает, что он содержит адрес коллекции, а не фактическую коллекцию. Поэтому, когда вы добавляете или удаляете элемент, вы меняете то, на что указывает указатель, а не сам указатель. Однако, если вы измените указатель, он будет изменен за пределами подпрограммы.
Вам не нужно беспокоиться об указателях. Все, что вам нужно знать, это то, как это влияет на поведение передачи параметра. Если для параметра коллекции ничего не задано, поведение зависит от того, использовали ли вы ByRef или ByVal.
- Использование ByRef сбросит исходную коллекцию
- Использование ByVal не изменит оригинальную коллекцию
' Очистит исходную коллекцию Sub PassByRef(ByRef coll As Collection) Set coll = Nothing End Sub ' Не изменит исходную коллекцию Sub PassByVal(ByVal coll As Collection) Set coll = Nothing End Sub
Возврат коллекции из функции
Возврат коллекции из функции — это то же самое, что вернуть любой объект. Вам нужно использовать ключевое слово Set. В следующем примере вы увидите, как вернуть коллекцию.
Sub OtchetOFruktah() ' ПРИМЕЧАНИЕ. Мы не используем ключевое слово New для создания 'коллекции. ' Коллекция создается в функции CreateCollection. Dim coll As Collection ' получить coll от функции CreateCollection Set coll = CreateCollection ' сделать что-то с coll здесь End Sub Function CreateCollection() As Collection Dim coll As New Collection coll.Add "Слива" coll.Add "Груша" ' Возврат коллекции Set CreateCollection = coll End Function
Примечание: вы не используете ключевое слово New при объявлении коллекции в подпункте OtchetOFruktah(). Потому что коллекция создается в CreateCollection (). Когда вы возвращаете коллекцию, вы просто назначаете переменную коллекции, указывающую на эту коллекцию.
Заключение
Коллекции — очень полезная часть VBA. Их гораздо проще использовать, чем массивы, и они очень полезны, когда вы много добавляете и удаляете элементы. У них есть только четыре свойства:
Add, Remove, Count и Item . Поэтому они очень просты в освоении.
Основные пункты этой статьи:
- Коллекции — это способ хранения группы элементов вместе.
- VBA имеет свои собственные коллекции, такие как
Workbooks, Worksheets и Cells . - Элементы не обязательно должны быть одного типа, но обычно одного. Коллекция VBA Sheets может содержать как листы, так и листы диаграмм.
- Коллекция позволяет легко выполнять одну и ту же задачу для нескольких элементов, например, распечатать все значения.
- Коллекции похожи на массивы, поскольку в них хранятся группы похожих элементов.
- Коллекции лучше при добавлении и удалении большого количества элементов.
- Коллекции проще в использовании, чем массивы.
- Массивы более полезны, когда количество элементов фиксировано.
- Массивы более эффективны при чтении и записи в ячейки или из них.
- Базовые типы данных (т.е. не-объекты) в коллекции доступны только для чтения, а массивы — для чтения / записи.
- Вы можете создать коллекцию, используя только Dim или Dim с помощью Set.
- Вы можете удалить всю коллекцию, установив для нее значение Nothing. Но зависит от того, как она была создана.
- Вы можете добавлять элементы в определенную позицию в коллекции, используя аргументы «Before» и «After» с помощью функции Add.
- Вы можете использовать ключи с коллекцией для прямого доступа к элементу. Коллекции не имеют хорошей поддержки ключей, поэтому обычно лучше использовать коллекцию Dictionary, когда вам нужно использовать ключи.
- Вы можете использовать циклы For и For Each для доступа ко всем элементам в коллекции. Цикл For Each более эффективен, но позволяет просматривать коллекцию только в одном порядке.
- Вы можете легко передать коллекцию в качестве аргумента в функцию или подпрограмму.
- Вы можете легко вернуть коллекцию из функции.
Коллекции (Collection) элементов Excel – это объект, представляющий из себя упорядоченный набор данных, на который можно ссылаться как на одно целое.
Отдельные элементы коллекции являются также объектами. Элементы коллекции никак между собой не связаны и могут иметь разные типы данных.
Примеры готовых коллекций в VBA: Workbooks, Worksheets, Range и Cells.
Коллекции похожи на массивы, поэтому важно понимать, что они из себя представляют и чем они отличаются от массивов.
Коллекции и массивы элементов в Excel
Коллекции и массивы используются для группировки переменных в Excel. Они оба хранят набор похожих данных, например список названий фруктов или фамилий сотрудников. Использование коллекции или массива позволяет работать с большим количеством данных в Excel , а также быстро и легко получать нужный результат.
Например, есть 100 учеников, которые получили оценки по предметам в году. Нужно задать переменные по ученикам, причем все они должны быть использованы по отдельности. Для того, чтобы не объявлять каждый раз переменную, можно использовать коллекцию или массив. Использование цикла с коллекцией или массивами означает, что вам нужна только одна строка для добавления или чтения значений.
' Создать массив правильного размера
Dim coll() As Long
ReDim coll(1 To StudentCount)
' Создать коллекцию Dim coll As New Collection
Рассмотрим отличия коллекций и массивов, чтобы определиться с их использованием.
- Количество данных, используемых в массиве или коллекции
Основное отличие состоит в том, что в массиве размер устанавливается один раз до того, как начнете добавлять элементы. Массивы используются, когда размер фиксирован.
Например, есть лист оценок учеников, на котором каждый ученик располагается на новой строке. В этом случае можно посчитать количество строк, чтобы получить количество студентов.
Рассмотрим другой пример, где мы не знаем количество заранее. Например, нужно сделать выборку по определенным предметам, а также в процессе обучения ученики могут быть добавлены или удалены из списка. Таким образом, данные по ученикам изменяются, поэтому вы не знаете, какой размер массива создать.
Вы можете создать массив максимально возможного размера. Проблема в том, что у вас будет много пустых переменных, с которыми придется что-то делать. Это очень неэффективно. Так что для этого примера лучше использовать коллекцию. Коллекция используется, когда размер часто изменяется.
Когда вы добавляете или удаляете элемент в коллекцию, макрос выполняет все изменения размера сам. Все, что вам нужно сделать, это добавить элемент или удалить его.
' Объявить Dim coll As New Collection ' Добавить элемент - VBA следит за изменением размера coll.Add "Яблоко" coll.Add "Слива" ' удалить элемент - VBA следит за изменением размера coll.Remove 1
- Использование данных в массивах и коллекциях
Основные типы данных (переменные, такие как string, date, long, currency и т.д.) в коллекциях доступны только для чтения. Вы можете добавить или удалить элемент, но не можете изменить его значение. Если вы собираетесь изменять значения в группе элементов, Вам нужно будет использовать массив. Коллекция только для чтения.
Создание коллекции
Вы можете объявить и создать коллекцию в одной строке:
Dim coll As New Collection
Вы также можете объявить и затем создать коллекцию, если и когда вам это нужно.
Dim coll As Collection 'Объявить
Set coll = New Collection 'Создать
Разница между этими методами заключается в следующем:
— в первом случае коллекция создается всегда;
— во втором случае коллекция создается только при соблюдении определенного условия (достижении строки Set). Например, If filefound = True Then Set coll = New Collection
Удаление всех элементов из коллекции
Чтобы удалить все элементы из коллекции, вы можете просто установить ее в новую коллекцию:
Set Coll = New Collection
Важно: если у нас есть две или более переменных, которые ссылаются на одну и ту же коллекцию, она не будет удалена (см. Очистка памяти в VBA).
Добавление элементов в коллекцию
С помощью свойства add, за которым следует добавляемое значение:
coll.Add "Яблоко"
coll.Add "Слива"
Каждый следующий элемент добавляется в следующий доступный индекс. В примере с фруктами яблоко добавляется в положение 1, а слива — в положение 2.
Вы можете использовать параметры «Before» или «After», чтобы указать, где вы хотите разместить элемент в коллекции:
- coll.Add «Лимон», Before:=1 ‘Добавить лимон перед первым пунктом.
После этого кода порядок коллекции выглядит так: 1.Лимон 2.Яблоко 3.Слива - coll.Add «Лимон», After:=1 ‘Добавьте лимон после первого пункта
После этого кода порядок коллекции выглядит так: 1.Яблоко 2. Лимон 3.Слива
Использование ключей для коллекции элементов Excel
Вы также можете добавить элементы, используя ключ:
collMark.Add Item:=45, Key:=»Петр»
Использование ключа позволяет получить доступ к элементу не зная его индекса, а просто задав его ключ. Даже если изменится индекс элемента (его порядковый номер), то по ключу мы все равно получим нужный элемент.
Важно: каждый ключ должен быть уникальным.
Преимущество использование ключей в том, что можно получить значение элемента коллекции напрямую и не искать его среди других элементов.
Недостатком использования ключей является то, что нельзя проверить, существует ли ключ.
Синтаксис добавления элементов в коллекцию
Collection.Add Элемент, [Ключ], [До], [После], где
- Collection – переменная, которая обозначает имя коллекции.
- Элемент (item) – обязательный аргумент, представляющий выражение любого типа, возвращающее элемент, который необходимо добавить в коллекцию.
- Ключ (key) – необязательный аргумент, представляющий строковое выражение, задающее уникальный ключ, который может использоваться вместо индекса позиции для доступа к элементу коллекции.
- До* (before) – необязательный аргумент, указывающий на позицию существующего элемента в коллекции, перед которым будет добавлен новый элемент.
- После* (after) – необязательный аргумент, указывающий на позицию существующего элемента в коллекции, после которого будет добавлен новый элемент.
* Аргументы «До» и «После» не могут применяться одновременно. Если аргументу «До» или «После» присвоено числовое значение, оно должно быть в пределах диапазона от 1 до значения свойства Collection.Count. Если это строка, она должна соответствовать одному из ключей существующих в коллекции элементов.
Доступ к элементам коллекции
Для доступа к элементам коллекции используется индекс — позиция элемента в коллекции на основе порядка, в котором они были добавлены.
Порядок также можно установить с помощью параметра «Before» или «After».
Чтобы напечатать элемент используется команда Debug.Print:
Debug.Print coll(1) или Debug.Print coll.Item(1)
Debug.Print coll(«Петр») ‘при использовании ключей
Для доступа ко всем элементам в коллекции вы можете использовать цикл For или цикл For Each.
Использование цикла For
For i = 1 To coll.Count Debug.Print coll(i) Next i
Использование цикла For Each
Dim fruit As Variant For Each fruit In coll Debug.Print fruit Next fruit