You are on page 1of 22

Excel VBA Dictionary – A Complete

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

Contents [hide] [hide]


 1 A Quick Guide to the VBA Dictionary
 2 What is the VBA Dictionary?
 3 A Dictionary in real world terms
 4 A Simple Example of using the VBA Dictionary
 5 Creating a Dictionary
o 5.1 Early versus Late Binding
 6 Adding Items to the Dictionary
 7 Assigning a Value
 8 Checking if a Key Exists
 9 Other useful functions
 10 The Key and Case Sensitivity
o 10.1 Things to Watch Out For
 11 Reading through the Dictionary
 12 Troubleshooting the Dictionary
o
 12.0.1 Missing Reference
 12.0.2 Exists is not Working
 12.0.3 Object Variable Error
 12.0.4 Useful Tips for Troubleshooting the Dictionary
 13 A Real World Dictionary Example
 14 When To Use The Dictionary
 15 What’s Next?
 16 Get the Free eBook

A Quick Guide to the VBA Dictionary


Function Params
Early binding reference “Microsoft Scripting Runtime”
(Add using Tools->References from the VB menu)
Declare (early binding) Dim dict As Scripting.Dictionary
Create(early binding) Set dict = New Scripting.Dictionary

Declare (late binding) Dim dict As Object


Create(late binding) Set dict =
CreateObject("Scripting.Dictionary")
Add item (key must not dict.Add Key, Value
already exist) e.g. dict.Add "Apples", 50
Change value at key. dict(Key) = Value
Automatically adds if the key e.g. dict("Oranges") = 60
does not exist.
Get a value from the dictionary Value = dict(Key)
using the key e.g. appleCount = dict("Apples")
Check if key exists dict.Exists(Key)
e.g. If dict.Exists("Apples") Then
Remove item dict.Remove Key
e.g. dict.Remove "Apples"

Remove all items dict.RemoveAll


Go through all items (for each Dim key As Variant
loop) For Each key In dict.Keys
Debug.Print key, dict(key)
Next key
Go through all items (for loop Dim i As Long
- early binding only) For i = 0 To dict.Count - 1
Debug.Print dict.Keys(i),
dict.Items(i)
Next i
Get the number of items dict.Count

Make key case sensitive (the dict.CompareMode = vbBinaryCompare


dictionary must be empty).
Make key non case sensitive dict.CompareMode = vbTextCompare
(the dictionary must be empty).
CLICK HERE TO DOWNLOAD THE TEST DATA FOR THIS POST

What is the VBA Dictionary?


In VBA we use Arrays and Collections to store groups of values. For example, we could use them to store a list of
customer names, student marks or a list of values from a range of cells.
A Dictionary is similar to a Collection. Using both types, we can name an item when we add it. Imagine we are storing the
count of different fruit types.

We could use both a Collection and a Dictionary like this

' Add to Dictionary

dict.Add Key:="Apple", Item:=5

' Add to Collection

coll.Add Item:=5, Key:="Apple"

Example of Key, Value pairs

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

' Get value from Dictionary


Total = dict("Apple")

' Get value from Collection

Total = coll("Apple")

So far so good. The Collection however, has two major faults

1. We cannot check if the key already exists.


2. We cannot change the value of an existing item.

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.

A Dictionary in real world terms


If you are still not clear about a Dictionary then think of it this way. A real world dictionary has a list of keys and items.
The Keys are the words and the Items are the definition.
When you want to find the definition of a word you go straight to that word. You don’t read through every item in the
Dictionary.
A second real world example is a phone book(remember those?). The Key in a phone book is the name\address and
the Item is the phone number. Again you use the name\address combination to quickly find a phone number.
In Excel the VLookup function works in a similar way to a Dictionary. You look up an item based on a unique value.

A Simple Example of using the VBA Dictionary


The code below give a simple but elegant example of using the Dictionary. It does the following

1. Adds three fruit types and a value for each to a Dictionary.


2. The user is asked to enter the name of a fruit.
3. The code checks if this fruit is in the Dictionary.
4. If yes then it displays the fruit name and the value.
5. If no then it informs the user the fruit does not exist.

Sub CheckFruit()

' Select Tools->References from the Visual Basic menu.

' Check box beside "Microsoft Scripting Runtime" in the list.

Dim dict As New Scripting.Dictionary

' Add to fruit to Dictionary

dict.Add key:="Apple", Item:=51

dict.Add key:="Peach", Item:=34

dict.Add key:="Plum,", Item:=43

Dim sFruit As String

' Ask user to enter fruit

sFruit = InputBox("Please enter the name of a fruit")

If dict.Exists(sFruit) Then

MsgBox sFruit & " exists and has value " & dict(sFruit)

Else

MsgBox sFruit & " does not exist."

End If

Set dict = Nothing

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.

1. Select Tools->References from the Visual Basic menu.


2. Find Microsoft Scripting Runtime in the list and place a check in the box beside it.

We declare a dictionary as follows

Dim dict As New Scripting.Dictionary

or

Dim dict As Scripting.Dictionary

Set dict = New Scripting.Dictionary

Creating a Dictionary this way is called “Early Binding”. There is also “Late Binding”. Let’s have a look at what this
means.

Early versus Late Binding


To create a Dictionary using Late binding we use the following code. We don’t need to add a reference.

Dim dict As Object

Set dict = CreateObject("Scripting.Dictionary")

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

1. Early binding requires a reference. Late binding doesn’t.


2. Early binding allows access to *Intellisense. Late binding doesn’t.
3. Early binding may require you to manually add the Reference to the “Microsoft Scripting Runtime” for some
users.

(*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 Key:="Orange", Item:=45

dict.Add "Apple", 66

dict.Add "12/12/2015", "John"

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

The following code will give this error

dict.Add Key:="Orange", Item:=45


' This line gives an error as key exists already

dict.Add Key:="Orange", Item:=75

Assigning a Value
Operation Format Example
Assign Dictionary(Key) = Item dict("Oranges") = 60

We can change the value of a key using the following code

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.

' Adds Orange to the dictionary

dict("Orange") = 45

' Changes the value of Orange to 100

dict("Orange") = 100

Checking if a Key Exists


Function Parameters Example
Exists Key If dict.Exists("Apples") Then

We can use the Exists function to check if a key exists in the dictionary

' Checks for the key 'Orange' in the dictionary

If dict.Exists("Orange") Then

MsgBox "The number of oranges is " & dict("Orange")


Else

MsgBox "There is no entry for Orange in the dictionary."

End If

Other useful functions


Function Parameters Example
Count N/A dict.Count

Remove Key dict.Remove "Apples"

RemoveAll N/A dict.RemoveAll

The three functions in the above table do the following:

1. Count – returns the number of items in the Dictionary.


2. Remove – removes a given key from the Dictionary.
3. RemoveAll – removes all items from the Dictionary

The following sub shows an example of how you would use these functions

Sub AddRemoveCount()

Dim dict As New Scripting.Dictionary

' Add some items

dict.Add "Orange", 55

dict.Add "Peach", 55

dict.Add "Plum", 55

Debug.Print "The number of items is " & dict.Count

' Remove one item

dict.Remove "Orange"

Debug.Print "The number of items is " & dict.Count

' Remove all items


dict.RemoveAll

Debug.Print "The number of items is " & dict.Count

End Sub

The Key and Case Sensitivity


Some of the string functions in VBA have a vbCompareMethod. This is used for functions that compare strings. It is used
to determine if the case of the letters matter.

© 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

' Prints False because it considers Orange and ORANGE different

Debug.Print dict.Exists("ORANGE")

Set dict = Nothing

End Sub

This time we use TextCompare which means that the case does not matter

Sub CaseMattersNot()

Dim dict As New Scripting.Dictionary

dict.CompareMode = TextCompare

dict.Add "Orange", 1

' Prints true because it considers Orange and ORANGE the same

Debug.Print dict.Exists("ORANGE")

Set dict = Nothing

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”.

Things to Watch Out For


BinaryCompare (the case matters) is the default and this can lead to subtle errors. For example, imagine you have the
following data in cells A1 to B2.
Orange, 5
orange, 12

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.

Dim dict As New Scripting.Dictionary

dict.add Key:=(Range("A1")), Item:=Range("B1")

dict.add Key:=(Range("A2")), Item:=Range("B2")

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.

Dim dict As New Scripting.Dictionary

dict.CompareMode = TextCompare

dict.add Key:=(Range("A1")), Item:=Range("B1")

' This line will give an error as your are trying to add the same key

dict.add Key:=(Range("A2")), Item:=Range("B2")

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()

Dim dict As New Scripting.Dictionary

dict.CompareMode = TextCompare

' Adds two keys

dict(Range("A1")) = Range("B1")

dict(Range("A2")) = Range("B2")

' Prints 2

Debug.Print dict.Count
End Sub

Reading through the Dictionary


We can read through all the items in the Dictionary. We can go through the keys using a For Each loop. We then use the
current key to access an item.

Dim k As Variant

For Each k In dict.Keys

' Print key and value

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

Debug.Print dict.Keys(i), dict.Items(i)

Next i

Troubleshooting the Dictionary


This section covers the common errors you may encounter using the Dictionary.

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.

Dim dict As New Scripting.Dictionary

Resolution: Select Tools->Reference from the Visual Basic menu. Place a check in the box beside “Microsoft Scripting
Runtime”.

See Section: Creating a Dictionary


Exists is not Working
Issue: You have added a key to the Dictionary but when you use the Exists function it returns false
This is normally an issue with Case Sensitivity(see above).
The following code adds “Apple” as a key. When we check for “apple” it returns false. This is because it takes the case of
the letters into account.

dict.Add "Apple", 4

If dict.Exists("apple") Then

MsgBox "Exists"

Else

MsgBox "Does not Exist"

End If

You can set the CompareMode property to TextCompare and this will ignore the case.

Dim dict As New Scripting.Dictionary

dict.CompareMode = TextCompare

Resolution: Set the CompareMode to TextCompare to ignore case or ensure your data has the correct case.

See Section: The Key and Case Sensitivity

Object Variable Error


Issue: You get the error message “Object variable or With block variable not set” when you try to use the Dictionary.
The normally happens when you forget to use New before you use the Dictionary. For example, the following code will
cause this error

Dim dict As Scripting.Dictionary

' This line will give "Object variable..." error

dict.Add "Apple", 4

Resolution: Use the New keyword when creating the Dictionary

Dim dict As New Scripting.Dictionary


Or

Dim dict As Scripting.Dictionary

Set dict = New Scripting.Dictionary

See Section: Creating a Dictionary

Useful Tips for Troubleshooting the Dictionary


If you are investigating an issue with the Dictionary it can be useful to see the contents.

Use the following sub to Print each Key and Item to the Immediate Window(Ctrl + G).

Sub PrintContents(dict As Scripting.Dictionary)

Dim k As Variant

For Each k In dict.Keys

' Print key and value

Debug.Print k, dict(k)

Next

End Sub

You can use it like this

Dim dict As Scripting.Dictionary

Set dict = New Scripting.Dictionary

' Add items to Dictionary here

' Print the contents of the Dictionary to the Immediate Window

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.

A Real World Dictionary Example


Let’s have a look at a real world example of using a dictionary. Our data for this example is the World Cup Final
matches from 2014.

CLICK HERE TO DOWNLOAD THE TEST DATA FOR THIS POST

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()

' Get worksheet

Dim wk As Worksheet

Set wk = ThisWorkbook.Worksheets("2014")
' Get range for all the matches

Dim rgMatches As Range

Set rgMatches = wk.Range("A1").CurrentRegion

Dim sTeam1 As String, sTeam2 As String

Dim lGoals1 As Long, lGoals2 As Long

Dim row As Range

For Each row In rgMatches.Rows

' read the data from each match

sTeam1 = row.Cells(1, 5)

sTeam2 = row.Cells(1, 9)

lGoals1 = row.Cells(1, 6)

lGoals2 = row.Cells(1, 7)

' Print each teams/goals to Immediate Window(Ctrl + G)

Debug.Print sTeam1, sTeam2, lGoals1, lGoals2

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

' If exists add to total

dict(sTeam1) = dict(sTeam1) + lGoals1

Else

' if doesn't exist then add

dict(sTeam1) = lGoals1

End If

We write out the values from the Dictionary to the worksheet as follows

Public Sub WriteDictionary(dict As Scripting.Dictionary _

, shReport As Worksheet)

shReport.Cells.Clear

Dim k As Variant, lRow As Long


lRow = 1

For Each k In dict.Keys

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

Public Sub SortByScore(shReport As Worksheet)

Dim rg As Range

Set rg = shReport.Range("A1").CurrentRegion

rg.sort rg.Columns("B"), xlDescending

End Sub

Our final GetTotals Sub looks like this

Sub GetTotals()

' Create dictionary

Dim dict As New Scripting.Dictionary

' Get worksheet

Dim sh As Worksheet

Set sh = ThisWorkbook.Worksheets("2014")

' Get range

Dim rgMatches As Range


Set rgMatches = sh.Range("A1").CurrentRegion

Dim sTeam1 As String, sTeam2 As String

Dim lGoals1 As Long, lGoals2 As Long

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

' If exists add to total

dict(sTeam1) = dict(sTeam1) + lGoals1

Else

' if doesn't exist then add

dict(sTeam1) = lGoals1

End If

If dict.Exists(sTeam2) Then

' If exists add to total

dict(sTeam2) = dict(sTeam2) + lGoals2

Else

' if doesn't exist then add

dict(sTeam2) = lGoals2

End If

Next i

' Get the report worksheet

Dim shReport As Worksheet

Set shReport = ThisWorkbook.Worksheets("Report")

' Write the teams and scores to the worksheet

WriteDictionary dict, shReport


' Sort the range

SortByScore shReport

' Clean up

Set dict = Nothing

End Sub

When you run this code you will get the following results

Teams ordered by number of goals scored

When To Use The Dictionary


So when should you use the VBA Dictionary? When you have a task where

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

You might also like