How to make your own collections in Excel VBA
There are many built-in collections in Excel (and other Office programs), and it is easy to make your own. Further down the page are examples that do just that, but first a few words about collections - what is a collection?
A collection is a group of objects that don't have to be the same data type. Excel has many built-in collections. For instance a workbook has a collection of worksheets, a worksheet has a collection of cells and so on.
In VBA you can address/refer to a worksheet by its number in the collection. For instance:
ActiveWorkbook.Worksheets(1).Visible
If you have named the sheet, you can also refer to it by name.
ActiveWorkbook.Worksheets("Data").Visible
There are many more built-in collections in Excel. For instance all control elements on a userform are items in the form's control elements collection.
Collections are not unlike arrays, because they contain a collection of objects that can be referenced with a numeric index, but collections are easier to handle, because they have some built-in methods to add, remove and reference the items.
You can add and remove objects, and you can loop through a collection using the fast "For Each...Next" loop. Every element (item) in a collection can have a key (optional name), which must be unique.
All collections have in common that you can add and remove items or be told, how many items there are in the collection:
colMyCollection.Add item, key, before, after
colMyCollection.Remove item, key
colMyCollection.Count
When you add an element, "item" is required, and it is the value returned when you ask for it. "Key" is an optional name. You don't have to name the item, but it can be very practical.The key must be unique and it must be a String (data type).
"Before" and "after" are used, if the new element shouldn't be added as the last item, but somewhere else in between.
Collection examples
The first example is very simple. The procedure reads the values in cell A1 and down, until it meets the first empty cell. After that it writes the values in cell C1 and down.
You can highlight/select the code using the mouse and copy (CTRL+C) it into a VBA module. Remember to write something in cell A1 and down - otherwise nothing will happen.
In the second example we only add unique values to our collection, and they are sorted alphabetically. But first the simple example:
Sub SimpleCollection()
Dim colMyCol As New Collection
Dim vElement
Dim rRange As Range
Dim rCell As Range
Dim lCount As Long
Set rRange = Range("A1")
If Len(rRange.Value) = 0 Then GoTo BeforeExit
If Len(rRange.Offset(1, 0).Value) > 0 Then
Set rRange = Range(rRange, rRange.End(xlDown))
End If
For Each rCell In rRange
colMyCol.Add rCell.Value
Next
For Each vElement In colMyCol
Range("C1").Offset(lCount, 0).Value = vElement
lCount = lCount + 1
Next
BeforeExit:
Set colMyCol = Nothing
Set rRange = Nothing
Set rCell = Nothing
Exit Sub
ErrorHandle:
MsgBox Err.Description & " Error in procedure _
SimpleCollection"
Resume BeforeExit
End Sub
Now that was easy. The next example is more advanced. It will only add unique values, and the values will be sorted alphabetically.
We do the unique value trick by adding the value as a name (key) too. In collections keys must be unique, and if you try to add a key that exists already, you will get an error. We get around this by using "On Error Resume Next".
We sort alphabetically by using the mathematical "<" less than, and then add the value before values later in the alphabet.
Insert the following in cell A1 and down. Copy the code to a VBA module.
London
Antwerp
1
New York
Antwerp
4
Bombay
Sub AdvancedCollection()
Dim colMyCol As New Collection
Dim rRange As Range
Dim rCell As Range
Dim lCount As Long
Dim sVar As String
On Error GoTo ErrorHandle
Set rRange = Range("A1")
If Len(rRange.Value) = 0 Then GoTo BeforeExit
If Len(rRange.Offset(1, 0).Value) > 0 Then
Set rRange = Range(rRange, rRange.End(xlDown))
End If
On Error Resume Next
For Each rCell In rRange
If IsNumeric(rCell.Value) Then
sVar = Str$(rCell.Value)
Else
sVar = rCell.Value
End If
With colMyCol
If .Count > 0 Then
For lCount = 1 To .Count
If rCell.Value < .Item(lCount) Then
.Add rCell.Value, sVar, lCount
Exit For
End If
Next
End If
If lCount = .Count + 1 Or .Count = 0 Then
.Add rCell.Value, sVar
End If
End With
Next
On Error GoTo ErrorHandle
Set rRange = Range("D1")
With colMyCol
For lCount = 0 To .Count
rRange.Offset(lCount, 0).Value = .Item(lCount + 1)
Next
End With
BeforeExit:
Set colMyCol = Nothing
Set rRange = Nothing
Set rCell = Nothing
Exit Sub
ErrorHandle:
MsgBox Err.Description & " Error in procedure AdvancedCollection"
Resume BeforeExit
End Sub
Tip
VBA distinguishes between lower and upper case, and if a word starts with lower case, it will go to the bottom. You can avoid that by writing:
Option Compare Text
at the top of the VBA module. This forces VBA not to use the default binary comparison.
Related:
|