Collections
Getting the Item Count of a Collection
Section titled “Getting the Item Count of a Collection”The number of items in a Collection can be obtained by calling its .Count function:
Syntax:
.Count()Sample Usage:
Public Sub Example() Dim foo As New Collection
With foo .Add "One" .Add "Two" .Add "Three" .Add "Four" End With
Debug.Print foo.Count 'Prints 4End SubDetermining if a Key or Item Exists in a Collection
Section titled “Determining if a Key or Item Exists in a Collection”Unlike a Scripting.Dictionary, a Collection does not have a method for determining if a given key exists or a way to retrieve keys that are present in the Collection. The only method to determine if a key is present is to use the error handler:
Public Function KeyExistsInCollection(ByVal key As String, _ ByRef container As Collection) As Boolean With Err If container Is Nothing Then .Raise 91 On Error Resume Next Dim temp As Variant temp = container.Item(key) On Error GoTo 0
If .Number = 0 Then KeyExistsInCollection = True ElseIf .Number <> 5 Then .Raise .Number End If End WithEnd FunctionThe only way to determine if an item is contained in a Collection is to iterate over the Collection until the item is located. Note that because a Collection can contain either primitives or objects, some extra handling is needed to avoid run-time errors during the comparisons:
Public Function ItemExistsInCollection(ByRef target As Variant, _ ByRef container As Collection) As Boolean Dim candidate As Variant Dim found As Boolean
For Each candidate In container Select Case True Case IsObject(candidate) And IsObject(target) found = candidate Is target Case IsObject(candidate), IsObject(target) found = False Case Else found = (candidate = target) End Select If found Then ItemExistsInCollection = True Exit Function End If NextEnd FunctionAdding Items to a Collection
Section titled “Adding Items to a Collection”Items are added to a Collection by calling its .Add method:
Syntax:
.Add(item, [key], [before, after])|Parameter|Description
|---|---|---|---|---|---|---|---|---|---
|item|The item to store in the Collection. This can be essentially any value that a variable can be assigned to, including primitive types, arrays, objects, and Nothing.
|key|Optional. A String that serves as a unique identifier for retrieving items from the Collection. If the specified key already exists in the Collection, it will result in a Run-time error 457: “This key is already associated with an element of this collection”.
|before|Optional. An existing key (String value) or index (numeric value) to insert the item before in the Collection. If a value is given, the after parameter must be empty or a Run-time error 5: “Invalid procedure call or argument” will result. If a String key is passed that does not exist in the Collection, a Run-time error 5: “Invalid procedure call or argument” will result. If a numeric index is passed that is does not exist in the Collection, a Run-time error 9: “Subscript out of range” will result.
|after|Optional. An existing key (String value) or index (numeric value) to insert the item after in the Collection. If a value is given, the before parameter must be empty. Errors raised are identical to the before parameter.
Notes:
Sample Usage:
Public Sub Example() Dim foo As New Collection
With foo .Add "One" 'No key. This item can only be retrieved by index. .Add "Two", "Second" 'Key given. Can be retrieved by key or index. .Add "Three", , 1 'Inserted at the start of the collection. .Add "Four", , , 1 'Inserted at index 2. End With
Dim member As Variant For Each member In foo Debug.Print member 'Prints "Three, Four, One, Two" NextEnd SubRemoving Items From a Collection
Section titled “Removing Items From a Collection”Items are removed from a Collection by calling its .Remove method:
Syntax:
.Remove(index)|Parameter|Description
|---|---|---|---|---|---|---|---|---|---
|index|The item to remove from the Collection. If the value passed is a numeric type or Variant with a numeric sub-type, it will be interpreted as a numeric index. If the value passed is a String or Variant containing a string, it will be interpreted as the a key. If a String key is passed that does not exist in the Collection, a Run-time error 5: “Invalid procedure call or argument” will result. If a numeric index is passed that is does not exist in the Collection, a Run-time error 9: “Subscript out of range” will result.
Notes:
- Removing an item from a
Collectionwill change the numeric indexes of all the items after it in theCollection.Forloops that use numeric indexes and remove items should run backwards (Step -1) to prevent subscript exceptions and skipped items. - Items should generally not be removed from a
Collectionfrom inside of aFor Eachloop as it can give unpredictable results.
Sample Usage:
Public Sub Example() Dim foo As New Collection
With foo .Add "One" .Add "Two", "Second" .Add "Three" .Add "Four" End With
foo.Remove 1 'Removes the first item. foo.Remove "Second" 'Removes the item with key "Second". foo.Remove foo.Count 'Removes the last item.
Dim member As Variant For Each member In foo Debug.Print member 'Prints "Three" NextEnd SubRetrieving Items From a Collection
Section titled “Retrieving Items From a Collection”Items can be retrieved from a Collection by calling the .Item function.
Syntax:
.Item(index)|Parameter|Description
|---|---|---|---|---|---|---|---|---|---
|index|The item to retrieve from the Collection. If the value passed is a numeric type or Variant with a numeric sub-type, it will be interpreted as a numeric index. If the value passed is a String or Variant containing a string, it will be interpreted as the a key. If a String key is passed that does not exist in the Collection, a Run-time error 5: “Invalid procedure call or argument” will result. If a numeric index is passed that is does not exist in the Collection, a Run-time error 9: “Subscript out of range” will result.
Notes:
.Itemis the default member ofCollection. This allows flexibility in syntax as demonstrated in the sample usage below.- Numeric indexes are 1-based.
- Keys are not case-sensitive.
.Item("Foo")and.Item("foo")refer to the same key. - The index parameter is not implicitly cast to a number from a
Stringor visa-versa. It is entirely possible that.Item(1)and.Item("1")refer to different items of theCollection.
Sample Usage (Indexes):
Public Sub Example() Dim foo As New Collection
With foo .Add "One" .Add "Two" .Add "Three" .Add "Four" End With
Dim index As Long For index = 1 To foo.Count Debug.Print foo.Item(index) 'Prints One, Two, Three, Four NextEnd SubSample Usage (Keys):
Public Sub Example() Dim keys() As String keys = Split("Foo,Bar,Baz", ",") Dim values() As String values = Split("One,Two,Three", ",")
Dim foo As New Collection Dim index As Long For index = LBound(values) To UBound(values) foo.Add values(index), keys(index) Next
Debug.Print foo.Item("Bar") 'Prints "Two"End SubSample Usage (Alternate Syntax):
Public Sub Example() Dim foo As New Collection
With foo .Add "One", "Foo" .Add "Two", "Bar" .Add "Three", "Baz" End With
'All lines below print "Two" Debug.Print foo.Item("Bar") 'Explicit call syntax. Debug.Print foo("Bar") 'Default member call syntax. Debug.Print foo!Bar 'Bang syntax.End SubNote that bang (!) syntax is allowed because .Item is the default member and can take a single String argument. The utility of this syntax is questionable.
Clearing All Items From a Collection
Section titled “Clearing All Items From a Collection”The easiest way to clear all of the items from a Collection is to simply replace it with a new Collection and let the old one go out of scope:
Public Sub Example() Dim foo As New Collection
With foo .Add "One" .Add "Two" .Add "Three" End With
Debug.Print foo.Count 'Prints 3 Set foo = New Collection Debug.Print foo.Count 'Prints 0End SubHowever, if there are multiple references to the Collection held, this method will only give you an empty Collection for the variable that is assigned.
Public Sub Example() Dim foo As New Collection Dim bar As Collection
With foo .Add "One" .Add "Two" .Add "Three" End With
Set bar = foo Set foo = New Collection
Debug.Print foo.Count 'Prints 0 Debug.Print bar.Count 'Prints 3End SubIn this case, the easiest way to clear the contents is by looping through the number of items in the Collection and repeatedly remove the lowest item:
Public Sub ClearCollection(ByRef container As Collection) Dim index As Long For index = 1 To container.Count container.Remove 1 NextEnd SubRemarks
Section titled “Remarks”A Collection is a container object that is included in the VBA runtime. No additional references are required in order to use it. A Collection can be used to store items of any data type and allows retrieval by either the ordinal index of the item or by using an optional unique key.
Feature Comparison with Arrays and Dictionaries
Section titled “Feature Comparison with Arrays and Dictionaries”||Collection|Array|Dictionary
|---|---|---|---|---|---|---|---|---|---
|Can be resized|Yes|Sometimes1|Yes
|Items are ordered|Yes|Yes|Yes2
|Items are strongly typed|No|Yes|No
|Items can be retrieved by ordinal|Yes|Yes|No
|New items can be inserted at ordinal|Yes|No|No
|How to determine if an item exists|Iterate all items|Iterate all items|Iterate all items
|Items can be retrieved by key|Yes|No|Yes
|Keys are case-sensitive|No|N/A|Optional3
|How to determine if a key exists|Error handler|N/A|.Exists function
|Remove all items|Iterate and .Remove|Erase, ReDim|.RemoveAll function
1 Only dynamic arrays can be resized, and only the last dimension of multi-dimensional arrays.
2 The underlying .Keys and .Items are ordered.
3 Determined by the .CompareMode property.