Professional Documents
Culture Documents
Guide
JANU ARY 6, 2016 BY PAU L KELLY ·2 2 COMMENTS
“The greatest masterpiece in literature is only a dictionary out of order.” – Jean Cocteau
In both cases, we are storing the value 5 and giving it the name “Apple”. We can now get the value of Apple from both
types like this
Total = coll("Apple")
The first issue is pretty easy to get around: Check Collection Key exists. The second is more difficult.
The VBA Dictionary does not have these issues. You can check if a Key exists and you can change the Item (Note: you
cannot change the Key itself).
For example, we can use the following code to check if we have an item called Apple.
If dict.Exists("Apple") Then
dict("Apple") = 78
These may seem very simple differences. However, it means that the Dictionary is very useful for certain tasks.
Particularly when we need to retrieve the value of an item.
Sub CheckFruit()
If dict.Exists(sFruit) Then
MsgBox sFruit & " exists and has value " & dict(sFruit)
Else
End If
End Sub
This is a simple example but it shows how useful a Dictionary is. We will see a real world example later in the post. Let’s
look at the basics of using a Dictionary.
Creating a Dictionary
To use the Dictionary you need to first add the reference.
or
Creating a Dictionary this way is called “Early Binding”. There is also “Late Binding”. Let’s have a look at what this
means.
In technical terms Early binding means we decide exactly what we are using up front. With Late binding this decision is
made when the application is running. In simple terms the difference is
(*Intellisense is the feature that shows you the available procedures and properties of an item as you are typing.)
Microsoft recommends that you use early binding in almost all cases.
Adding Items to the Dictionary
Function Params Example
Add Key, Item dict.Add "Apples", 50
We can add items to the dictionary using the Add function. Items can also be added by assigning a value which we will
look at in the next section.
Let’s look at the Add function first. The Add function has two parameters: Key and Item. Both must be supplied
dict.Add "Apple", 66
dict.Add 1, 45.56
In the first add example above we use the parameter names. You don’t have to do this although it can be helpful when you
are starting out.
The Key can be any data type. The Item can be any data type, an object, array, collection or even a dictionary. So you
could have a Dictionary of Dictionaries, Array and Collections. But most of the time it will be a value(date, number or
text).
If we add a Key that already exists in the Dictionary then we will get the error
Assigning a Value
Operation Format Example
Assign Dictionary(Key) = Item dict("Oranges") = 60
dict("Orange") = 75
Assigning a value to Key this way has an extra feature. If the Key does not exist it automatically adds the Key and Item to
the dictionary. This would be useful where you had a list of sorted items and only wanted the last entry for each one.
dict("Orange") = 45
dict("Orange") = 100
We can use the Exists function to check if a key exists in the dictionary
If dict.Exists("Orange") Then
End If
The following sub shows an example of how you would use these functions
Sub AddRemoveCount()
dict.Add "Orange", 55
dict.Add "Peach", 55
dict.Add "Plum", 55
dict.Remove "Orange"
End Sub
© BigStockPhoto.com
The Dictionary uses a similar method. The CompareMode property of the Dictionary is used to determine if the case of
the key matters. The settings are
TextCompare: Upper and lower case are considered the same.
BinaryCompare: Upper and lower case are considered different. This is the default.
With the Dictionary we can use these settings to determine if the case of the key matters.
Sub CaseMatters()
Dim dict As New Scripting.Dictionary
dict.CompareMode = BinaryCompare
dict.Add "Orange", 1
Debug.Print dict.Exists("ORANGE")
End Sub
This time we use TextCompare which means that the case does not matter
Sub CaseMattersNot()
dict.CompareMode = TextCompare
dict.Add "Orange", 1
' Prints true because it considers Orange and ORANGE the same
Debug.Print dict.Exists("ORANGE")
End Sub
Note: The Dictionary must be empty when you use the CompareMode property or you will get the error: “Invalid
procedure call or argument”.
The following code will create two keys – on for “Orange” and one for “orange”. This is subtle as the only difference is
the case of the first letter.
If you do use TextCompare for the same data you will get an error when you try to add the second key as it considers
“Orange” and “orange” the same.
dict.CompareMode = TextCompare
' This line will give an error as your are trying to add the same key
If you use the assign method then it does not take the CompareMode into account. So the following code will still add
two keys even though the CompareMode is set to TextCompare.
Sub Assign()
dict.CompareMode = TextCompare
dict(Range("A1")) = Range("B1")
dict(Range("A2")) = Range("B2")
' Prints 2
Debug.Print dict.Count
End Sub
Dim k As Variant
Debug.Print k, dict(k)
Next
We can also loop through the keys although this only works with Early Binding.
Dim i As Long
For i = 0 To dict.Count - 1
Next i
Missing Reference
Issue: You get the error message “User-defined type not defined”
This normally happens when you create the Dictionary but forget to add the reference.
Resolution: Select Tools->Reference from the Visual Basic menu. Place a check in the box beside “Microsoft Scripting
Runtime”.
dict.Add "Apple", 4
If dict.Exists("apple") Then
MsgBox "Exists"
Else
End If
You can set the CompareMode property to TextCompare and this will ignore the case.
dict.CompareMode = TextCompare
Resolution: Set the CompareMode to TextCompare to ignore case or ensure your data has the correct case.
dict.Add "Apple", 4
Use the following sub to Print each Key and Item to the Immediate Window(Ctrl + G).
Dim k As Variant
Debug.Print k, dict(k)
Next
End Sub
PrintContents dict
If you are stepping through the code you can also add dict.Count to the Watch Window to see how many items are
currently in the Dictionary. Right-click anywhere in the code window and select Add Watch. Type dict.Count into the
text box and click Ok.
You can also use the Dictionary itself as a Watch. Add Dict to the Watch window. If you click on the plus sign you will
see the contents of the Dictionary. This can be useful but it only shows the key and not the item.
Note: You can only view Watches when the code is running.
Our task here is to get the number of goals scored by each team.
The first thing we need to do is to read all the data. The following code reads through all the matches and prints the names
of the two teams involved.
Sub GetTotals()
Dim wk As Worksheet
Set wk = ThisWorkbook.Worksheets("2014")
' Get range for all the matches
sTeam1 = row.Cells(1, 5)
sTeam2 = row.Cells(1, 9)
lGoals1 = row.Cells(1, 6)
lGoals2 = row.Cells(1, 7)
Next row
End Sub
What we want to do now is to store each team and the goals they scored. When we meet a team for the first time we add
the name as a Key and the number of goals as the Item.
Celebrating a Goal | © BigStockPhoto.com
If the team has already been added then we add the goals they scored in the current match to their total.
Using a Dictionary, we can easily check if the team already exists. We can also update the value for this team.
If dict.Exists(sTeam1) Then
Else
dict(sTeam1) = lGoals1
End If
We write out the values from the Dictionary to the worksheet as follows
, shReport As Worksheet)
shReport.Cells.Clear
shReport.Cells(lRow, 1) = k
shReport.Cells(lRow, 2) = dict(k)
lRow = lRow + 1
Next
End Sub
We obviously want the scores to be sorted. It is much easier to read this way. There is no easy way to sort a Dictionary.
The way to do it is to copy all the items to an array. Sort the array and copy the items back to a Dictionary.
What we can do is sort the data once it has been written to the worksheet. We can use the following code to do this
Dim rg As Range
Set rg = shReport.Range("A1").CurrentRegion
End Sub
Sub GetTotals()
Dim sh As Worksheet
Set sh = ThisWorkbook.Worksheets("2014")
Dim i As Long
For i = 2 To rgMatches.Rows.Count
sTeam1 = rgMatches.Cells(i, 5)
sTeam2 = rgMatches.Cells(i, 9)
lGoals1 = rgMatches.Cells(i, 6)
lGoals2 = rgMatches.Cells(i, 7)
If dict.Exists(sTeam1) Then
Else
dict(sTeam1) = lGoals1
End If
If dict.Exists(sTeam2) Then
Else
dict(sTeam2) = lGoals2
End If
Next i
SortByScore shReport
' Clean up
End Sub
When you run this code you will get the following results
1. You have a list of unique items e.g. countries, invoice numbers, customer name and addresses, project ids,
product names etc.
2. You need to retrieve the value of a unique item.
Key/Values of Countries and Land area in Km2