“The greatest masterpiece in literature is only a dictionary out of order.” – Jean Cocteau
A Quick Guide to the VBA Dictionary
Function | Example |
---|---|
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 already exist) | dict.Add Key, Value e.g. dict.Add «Apples», 50 |
Change value at key. Automatically adds if the key does not exist. | dict(Key) = Value e.g. dict(«Oranges») = 60 |
Get a value from the dictionary using the key | Value = dict(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 loop) | Dim key As Variant For Each key In dict.Keys Debug.Print key, dict(key) Next key |
Go through all items (for loop — early binding only) | Dim i As Long For i = 0 To dict.Count — 1 Debug.Print dict.Keys(i), dict.Items(i) Next i |
Go through all items (for loop — early and late binding) | Dim i As Long 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 dictionary must be empty). | dict.CompareMode = vbBinaryCompare |
Make key non case sensitive (the dictionary must be empty). | dict.CompareMode = vbTextCompare |
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
- We cannot check if the key already exists.
- 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 and the Key.
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.
Download the Source Code
Dictionary Webinar
If you are a member of the VBA Vault, then click on the image below to access the webinar and the associated source code.
(Note: Website members have access to the full webinar archive.)
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 nameaddress and the Item is the phone number. Again you use the nameaddress 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
- Adds three fruit types and a value for each to a Dictionary.
- The user is asked to enter the name of a fruit.
- The code checks if this fruit is in the Dictionary.
- If yes then it displays the fruit name and the value.
- If no then it informs the user the fruit does not exist.
' https://excelmacromastery.com/ 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.
- Select Tools->References from the Visual Basic menu.
- 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 in 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
- Early binding requires a reference. Late binding doesn’t.
- Early binding allows access to *Intellisense. Late binding doesn’t.
- 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.)
While Microsoft recommends that you use early binding in almost all cases I would differ. A good rule of thumb is to use early binding when developing the code so that you have access to the Intellisense. Use late binding when distributing the code to other users to prevent various library conflict errors occurring.
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
Don’t forget that you can download all the VBA code used in this post from the top or bottom of the post.
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
Storing Multiple Values in One Key
Take a look at the sample data below. We want to store the Amount and Items for each Customer ID.
The Dictionary only stores one value so what can we do?
We could use an array or collection as the value but this is unnecessary. The best way to do it is to use a Class Module.
The following code shows how we can do this
' clsCustomer Class Module Code Public CustomerID As String Public Amount As Long Public Items As Long
' Create a new clsCustomer object Set oCust = New clsCustomer ' Set the values oCust.CustomerID = rg.Cells(i, 1).Value oCust.Amount = rg.Cells(i, 2).Value oCust.Items = rg.Cells(i, 3).Value ' Add the new clsCustomer object to the dictionary dict.Add oCust.CustomerID, oCust
You can see that by using the Class Module we can store as many fields as we want. Examples 2 and 3 at the bottom of the post show how to use a class module with a Dictionary
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:
- Count – returns the number of items in the Dictionary.
- Remove – removes a given key from the Dictionary.
- RemoveAll – removes all items from the Dictionary
The following sub shows an example of how you would use these functions
' https://excelmacromastery.com/ 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
Remember that you can download all the code examples from the post. Just go to the download section at the top.
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
vbTextCompare: Upper and lower case are considered the same.
vbBinaryCompare: 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.
' https://excelmacromastery.com/ Sub CaseMatters() Dim dict As New Scripting.Dictionary dict.CompareMode = vbBinaryCompare 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 vbTextCompare which means that the case does not matter
' https://excelmacromastery.com/ Sub CaseMattersNot() Dim dict As New Scripting.Dictionary dict.CompareMode = vbTextCompare 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
vbBinaryCompare (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.
' https://excelmacromastery.com/ Sub DiffCase() Dim dict As New Scripting.Dictionary dict.Add Key:=(Range("A1")), Item:=Range("B1") dict.Add Key:=(Range("A2")), Item:=Range("B2") End Sub
If you do use vbTextCompare 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.
' https://excelmacromastery.com/ Sub UseTextcompare() Dim dict As New Scripting.Dictionary dict.CompareMode = vbTextCompare 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") End Sub
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 vbTextCompare.
' https://excelmacromastery.com/ Sub Assign() Dim dict As New Scripting.Dictionary dict.CompareMode = vbTextCompare ' 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(Update Feb 2020: In Office 365 this now works with both versions):
Dim i As Long For i = 0 To dict.Count - 1 Debug.Print dict.Keys(i), dict.Items(i) Next i
This method works with both Early and Late binding:
Dim i As Long For i = 0 To dict.Count - 1 Debug.Print dict.Keys()(i), dict.Items()(i) Next i
Sorting the Dictionary
Sometimes you may wish to sort the Dictionary either by key or by value.
The Dictionary doesn’t have a sort function so you have to create your own. I have written two sort functions – one for sorting by key and one for sorting by value.
Sorting by keys
To sort the dictionary by the key you can use the SortDictionaryByKey function below
' https://excelmacromastery.com/ Public Function SortDictionaryByKey(dict As Object _ , Optional sortorder As XlSortOrder = xlAscending) As Object Dim arrList As Object Set arrList = CreateObject("System.Collections.ArrayList") ' Put keys in an ArrayList Dim key As Variant, coll As New Collection For Each key In dict arrList.Add key Next key ' Sort the keys arrList.Sort ' For descending order, reverse If sortorder = xlDescending Then arrList.Reverse End If ' Create new dictionary Dim dictNew As Object Set dictNew = CreateObject("Scripting.Dictionary") ' Read through the sorted keys and add to new dictionary For Each key In arrList dictNew.Add key, dict(key) Next key ' Clean up Set arrList = Nothing Set dict = Nothing ' Return the new dictionary Set SortDictionaryByKey = dictNew End Function
The code below, shows you how to use SortDictionaryByKey
' https://excelmacromastery.com/ Sub TestSortByKey() Dim dict As Object Set dict = CreateObject("Scripting.Dictionary") dict.Add "Plum", 99 dict.Add "Apple", 987 dict.Add "Pear", 234 dict.Add "Banana", 560 dict.Add "Orange", 34 PrintDictionary "Original", dict ' Sort Ascending Set dict = SortDictionaryByKey(dict) PrintDictionary "Key Ascending", dict ' Sort Descending Set dict = SortDictionaryByKey(dict, xlDescending) PrintDictionary "Key Descending", dict End Sub Public Sub PrintDictionary(ByVal sText As String, dict As Object) Debug.Print vbCrLf & sText & vbCrLf & String(Len(sText), "=") Dim key As Variant For Each key In dict.keys Debug.Print key, dict(key) Next End Sub
Sorting by values
To sort the dictionary by the values you can use the SortDictionaryByValue function below.
' https://excelmacromastery.com/ Public Function SortDictionaryByValue(dict As Object _ , Optional sortorder As XlSortOrder = xlAscending) As Object On Error GoTo eh Dim arrayList As Object Set arrayList = CreateObject("System.Collections.ArrayList") Dim dictTemp As Object Set dictTemp = CreateObject("Scripting.Dictionary") ' Put values in ArrayList and sort ' Store values in tempDict with their keys as a collection Dim key As Variant, value As Variant, coll As Collection For Each key In dict value = dict(key) ' if the value doesn't exist in dict then add If dictTemp.exists(value) = False Then ' create collection to hold keys ' - needed for duplicate values Set coll = New Collection dictTemp.Add value, coll ' Add the value arrayList.Add value End If ' Add the current key to the collection dictTemp(value).Add key Next key ' Sort the value arrayList.Sort ' Reverse if descending If sortorder = xlDescending Then arrayList.Reverse End If dict.RemoveAll ' Read through the ArrayList and add the values and corresponding ' keys from the dictTemp Dim item As Variant For Each value In arrayList Set coll = dictTemp(value) For Each item In coll dict.Add item, value Next item Next value Set arrayList = Nothing ' Return the new dictionary Set SortDictionaryByValue = dict Done: Exit Function eh: If Err.Number = 450 Then Err.Raise vbObjectError + 100, "SortDictionaryByValue" _ , "Cannot sort the dictionary if the value is an object" End If End Function
The code below shows you how to use SortDictionaryByValue
' https://excelmacromastery.com/ Sub TestSortByValue() Dim dict As Object Set dict = CreateObject("Scripting.Dictionary") dict.Add "Plum", 99 dict.Add "Apple", 987 dict.Add "Pear", 234 dict.Add "Banana", 560 dict.Add "Orange", 34 PrintDictionary "Original", dict ' Sort Ascending Set dict = SortDictionaryByValue(dict) PrintDictionary "Value Ascending", dict ' Sort Descending Set dict = SortDictionaryByValue(dict, xlDescending) PrintDictionary "Value Descending", dict End Sub Public Sub PrintDictionary(ByVal sText As String, dict As Object) Debug.Print vbCrLf & sText & vbCrLf & String(Len(sText), "=") Dim key As Variant For Each key In dict.keys Debug.Print key, dict(key) Next key End Sub
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 vbTextCompare and this will ignore the case:
Dim dict As New Scripting.Dictionary dict.CompareMode = vbTextCompare
Resolution: Set the CompareMode to vbTextCompare 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).
' https://excelmacromastery.com/ 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.
Remember that you can download all the code examples from the post. Just go to the download section at the top.
Copying the Dictionary to an Array
As we know the dictionary is made up of Key and Value pairs. The dictionary has a Keys property which is an array of all the keys and an Items property which is an array of all the items(i.e. values).
As both of these properties are arrays, we can write them directly to a worksheet as we will see in the next section.
If we want to copy either the Keys or Items array to a new array then we can do it very easily like this:
Dim arr As Variant arr = dict.Keys
The following example copies the Keys and Items arrays to new arrays. Then the contents of the new arrays are printed to the Immediate Window:
Sub DictionaryToArray() ' Create dictionary and add entries Dim dict As New Dictionary dict.Add "France", 56 dict.Add "USA", 23 dict.Add "Australia", 34 ' Declare variant to use as array Dim arr As Variant ' Copy keys to array arr = dict.Keys ' Print array to Immediate Window(Ctrl + G to View) Call PrintArrayToImmediate(arr, "Keys:") ' Copy items to array arr = dict.Items ' Print array to Immediate Window(Ctrl + G to View) Call PrintArrayToImmediate(arr, "Items:") End Sub ' Prints an array to the Immediate Window(Ctrl + G to View) Sub PrintArrayToImmediate(arr As Variant, headerText As String) Debug.Print vbNewLine & headerText Dim entry As Variant For Each entry In arr Debug.Print entry Next End Sub
When you run the code you wil get the following output:
Note that you can only copy the Items array when it contains basic data types like string, long, date, double etc. If the items are objects then you can not copy them to an array. You’ll need to read through the dictionary using a loop instead.
Writing the Dictionary to the Worksheet
We can write the Dictionary keys or items to the worksheet in one line of code.
When you write out the keys or items they will be written to a row. If you want to write them to a column you can use the WorksheetFunction.Transpose function.
The code below shows examples of how to write the Dictionary to a worksheet:
Sub DictionaryToWorksheet() Dim dict As New Dictionary dict.Add "France", 56 dict.Add "USA", 23 dict.Add "Australia", 34 Dim sh As Worksheet Set sh = ThisWorkbook.Worksheets("Sheet1") ' Write keys to range A1:C1 sh.Range("A1:C1").Value = dict.Keys ' Write items to range A2:C2 sh.Range("A2:C2").Value = dict.Items ' Write keys to range E1:E3 sh.Range("E1:E3").Value = WorksheetFunction.Transpose(dict.Keys) ' Write items to range F1:F3 sh.Range("F1:F3").Value = WorksheetFunction.Transpose(dict.Items) End Sub
Useful Dictionary Examples
The easiest way to see the benefits of the Dictionary is to see some real-world examples of it’s use. So in this section we are going to look at some examples. You can get workbooks and code for these examples by entering your email below:
Example 1 – Summing Single Values
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.
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.
' https://excelmacromastery.com/vba-dictionary ' Reads the World Cup data from the 2014 Worksheet ' View the results in the Immediate Window(Ctrl + G) Sub GetTotals() ' Get worksheet Dim wk As Worksheet Set wk = ThisWorkbook.Worksheets("2014") ' Get range for all the matches Dim rg As Range Set rg = wk.Range("A1").CurrentRegion Dim Team1 As String, Team2 As String Dim Goals1 As Long, Goals2 As Long Dim i As Long For i = 2 To rg.Rows.Count ' read the data from each match Team1 = rg.Cells(i, 5).Value Team2 = rg.Cells(i, 9).Value Goals1 = rg.Cells(i, 6).Value Goals2 = rg.Cells(i, 7).Value ' Print each teams/goals to Immediate Window(Ctrl + G) Debug.Print Team1, Team2, Goals1, Goals2 Next i 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.
We can use the following line to add goals to the current team:
dict(Team1) = dict(Team1) + Goals1
This line is very powerful.
If the teams exists in the Dictionary, the current goals are added to the current total for that team.
If the team does not exist in the Dictionary then it will automatically add the team to the Dictionary and set the value to the goals.
For example, imagine the Dictionary has one entry
Key, Value
Brazil, 5
Then
dict("Brazil") = dict("Brazil") + 3
will update the dictionary so it now looks like this
Key, Value
Brazil, 8
The line
dict("France") = dict("France") + 3
will update the dictionary so it now looks like this
Key, Value
Brazil, 8
France, 3
This saves us having to write code like this:
If dict.Exists(Team1) Then ' If exists add to total dict(Team) = dict(Team) + Goals1 Else ' if doesn't exist then add dict(Team) = Goals1 End If
We write out the values from the Dictionary to the worksheet as follows:
' Write the data from the dictionary to the worksheet ' https://excelmacromastery.com/vba-dictionary Private Sub WriteDictionary(dict As Scripting.Dictionary _ , shReport As Worksheet) ' Write the keys shReport.Range("A1").Resize(dict.Count, 1).Value = WorksheetFunction.Transpose(dict.Keys) ' Write the items shReport.Range("B1").Resize(dict.Count, 1).Value = WorksheetFunction.Transpose(dict.Items) 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:
' Sort the data on the worksheet ' https://excelmacromastery.com/vba-dictionary Public Sub SortByScore(shReport As Worksheet _ , Optional sortOrder As XlSortOrder = xlDescending) Dim rg As Range Set rg = shReport.Range("A1").CurrentRegion rg.Sort rg.Columns("B"), sortOrder End Sub
Our final GetTotals sub looks like this:
' https://excelmacromastery.com/vba-dictionary Sub GetTotalsFinal() ' 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 team1 As String, team2 As String Dim goals1 As Long, goals2 As Long Dim i As Long ' Read through the range of data For i = 2 To rgMatches.Rows.Count ' read the data to variables team1 = rgMatches.Cells(i, 5).Value team2 = rgMatches.Cells(i, 9).Value goals1 = rgMatches.Cells(i, 6).Value goals2 = rgMatches.Cells(i, 7).Value ' Add the totals for each team to the dictionary. ' If the team doesn't exist it will be automatically added dict(team1) = dict(team1) + goals1 dict(team2) = dict(team2) + goals2 Next i ' Get the report worksheet Dim shReport As Worksheet Set shReport = ThisWorkbook.Worksheets("2014 Report") ' Write the teams and scores to the worksheet WriteDictionary dict, shReport ' Sort the range ' Change to xlAscending to reverse the order SortByScore shReport, xlDescending ' Clean up Set dict = Nothing shReport.Activate End Sub
When you run this code you will get the following results
Teams ordered by number of goals scored
Example 2 – Dealing with Multiple Values
We are going to use the data from the Multiple Values section above
Imagine this data starts at cell A1. Then we can use the code below to read to the dictionary.
The code includes two subs for displaying the data:
- WriteToImmediate prints the contents of the dictionary to the Immediate Window.
- WriteToWorksheet writes the contents of the dictionary to the worksheet called Output.
To run this example:
- Create a worksheet called Customers.
- Add the above data to the worksheet starting at cell A1.
- Create a worksheet called Output and leave it blank.
- Go to the Visual Basic Editor(Alt + F11).
- Select Tools->Reference and then check “Microsoft Scripting Runtime” from the list.
- Create a new class module and add the first piece of code from below.
- Create a new standard module and add the second piece of code from below.
- Press F5 to run and select Main from the menu.
- Check the ImmediateWindow(Ctrl + G) and the Output worksheet to see the results.
' clsCustomer Class Module Code Public CustomerID As String Public Amount As Long Public Items As Long
' Standard module Code ' https://excelmacromastery.com/ Sub Main() Dim dict As Dictionary ' Read the data to the dictionary Set dict = ReadMultiItems ' Write the Dictionary contents to the Immediate Window(Ctrl + G) WriteToImmediate dict ' Write the Dictionary contents to a worksheet WriteToWorksheet dict, ThisWorkbook.Worksheets("Output") End Sub Private Function ReadMultiItems() As Dictionary ' Declare and create the Dictionary Dim dict As New Dictionary ' Get the worksheet Dim sh As Worksheet Set sh = ThisWorkbook.Worksheets("Customers") ' Get the range of all the adjacent data using CurrentRegion Dim rg As Range Set rg = sh.Range("A1").CurrentRegion Dim oCust As clsCustomer, i As Long ' read through the data For i = 2 To rg.Rows.Count ' Create a new clsCustomer object Set oCust = New clsCustomer ' Set the values oCust.CustomerID = rg.Cells(i, 1).Value oCust.Amount = rg.Cells(i, 2).Value oCust.Items = rg.Cells(i, 3).Value ' Add the new clsCustomer object to the dictionary dict.Add oCust.CustomerID, oCust Next i ' Return the dictionary to the Main sub Set ReadMultiItems = dict End Function ' Write the Dictionary contents to the Immediate Window(Ctrl + G) ' https://excelmacromastery.com/ Private Sub WriteToImmediate(dict As Dictionary) Dim key As Variant, oCust As clsCustomer ' Read through the dictionary For Each key In dict.Keys Set oCust = dict(key) With oCust ' Write to the Immediate Window (Ctrl + G) Debug.Print .CustomerID, .Amount, .Items End With Next key End Sub ' Write the Dictionary contents to a worksheet ' https://excelmacromastery.com/ Private Sub WriteToWorksheet(dict As Dictionary, sh As Worksheet) ' Delete all existing data from the worksheet sh.Cells.ClearContents Dim row As Long row = 1 Dim key As Variant, oCust As clsCustomer ' Read through the dictionary For Each key In dict.Keys Set oCust = dict(key) With oCust ' Write out the values sh.Cells(row, 1).Value = .CustomerID sh.Cells(row, 2).Value = .Amount sh.Cells(row, 3).Value = .Items row = row + 1 End With Next key End Sub
Example 3 – Summing Multiple Values
In this example were are going to make a small update to Example 2. In that example there was only one entry per customer in the data.
This time there will be multiple entries for some customers and we want to sum the total Amount and total Items for each customer.
See the updated dataset below:
Note: If you run the “Example 2” code on data with multiple copies of the CustomerID, it will give the “Key already exists error”.
' clsCustomer Class Module Code Public CustomerID As String Public Amount As Long Public Items As Long
' Read from worksheet: CustomerSum ' Write to worksheet: CustomerRepSum ' https://excelmacromastery.com/vba-dictionary Sub MainSum() Dim dict As Dictionary ' Read the data to the dictionary Set dict = ReadMultiItemsSum ' Write the Dictionary contents to the Immediate Window(Ctrl + G) WriteToImmediate dict ' Write the Dictionary contents to a worksheet WriteToWorksheet dict, ThisWorkbook.Worksheets("CustomerRepSum") End Sub ' Read multiple items but this time sums the items ' https://excelmacromastery.com/ Private Function ReadMultiItemsSum() As Dictionary ' Declare and Create the Dictionary Dim dict As New Dictionary ' Get the worksheet Dim sh As Worksheet Set sh = ThisWorkbook.Worksheets("CustomerSum") ' Get the range of all the adjacent data using CurrentRegion Dim rg As Range Set rg = sh.Range("A1").CurrentRegion Dim oCust As clsCustomer, i As Long, customerID As String ' read through the data For i = 2 To rg.Rows.Count customerID = rg.Cells(i, 1).Value ' check if the customerID has been added already If dict.Exists(customerID) = True Then ' Get the existing customer object Set oCust = dict(customerID) Else ' Create a new clsCustomer object Set oCust = New clsCustomer ' Add the new clsCustomer object to the dictionary dict.Add customerID, oCust End If ' Set the values oCust.Amount = oCust.Amount + rg.Cells(i, 2).Value oCust.Items = oCust.Items + rg.Cells(i, 3).Value Next i ' Return the dictionary to the Main sub Set ReadMultiItemsSum = dict End Function ' Write the Dictionary contents to the Immediate Window(Ctrl + G) ' https://excelmacromastery.com/vba-dictionary Private Sub WriteToImmediate(dict As Dictionary) Dim key As Variant, oCust As clsCustomer ' Read through the dictionary For Each key In dict.Keys Set oCust = dict(key) With oCust ' Write to the Immediate Window (Ctrl + G) Debug.Print key, .Amount, .Items End With Next key End Sub ' Write the Dictionary contents to a worksheet ' https://excelmacromastery.com/ Private Sub WriteToWorksheet(dict As Dictionary, sh As Worksheet) ' Delete all existing data from the worksheet sh.Cells.ClearContents Dim row As Long row = 1 Dim key As Variant, oCust As clsCustomer ' Read through the dictionary For Each key In dict.Keys Set oCust = dict(key) With oCust ' Write out the values sh.Cells(row, 1).Value = key sh.Cells(row, 2).Value = .Amount sh.Cells(row, 3).Value = .Items row = row + 1 End With Next key End Sub
When To Use The Dictionary
So when should you use the VBA Dictionary? When you have a task where:
- You have a list of unique items e.g. countries, invoice numbers, customer name and addresses, project ids, product names etc.
- You need to retrieve the value of a unique item.
Key/Values of Countries and Land area in Km2
What’s Next?
Free VBA Tutorial If you are new to VBA or you want to sharpen your existing VBA skills then why not try out the The Ultimate VBA Tutorial.
Related Training: Get full access to the Excel VBA training webinars and all the tutorials.
(NOTE: Planning to build or manage a VBA Application? Learn how to build 10 Excel VBA applications from scratch.)
borro Пользователь Сообщений: 198 |
Здравствуйте. Расскажите или укажите, есть ли где сравнительное сопоставление трех понятий: массив, коллекция, словарь. Изменено: borro — 26.01.2017 02:14:53 |
The_Prist Пользователь Сообщений: 14181 Профессиональная разработка приложений для 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 Пользователь Сообщений: 23249 |
#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 Пользователь Сообщений: 14181 Профессиональная разработка приложений для 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 Пользователь Сообщений: 14181 Профессиональная разработка приложений для MS Office |
#20 28.01.2017 11:19:13
А вопрос был какой последний?
Вы все же получили после этого ответ от Alex_ST — словари.
Но отписаться понятно-непонятно, оно-не оно уже не посчитали нужным. А между тем это проявление элементарной вежливости и уважения к отвечающим — отписаться ответившему: помогло — не помогло, понятно — не понятно и т.п. Чтобы все понимали имеет ли смысл дальше что-то предлагать или обсуждать. Т.к. Вы этого не делаете — тема развивается своим ходом, а Вас берут на заметку — типа это тот человек, который темы создает, ответы получает и сваливает. В результате что будет? Правильно. Вам просто перестанут отвечать, ибо потребительское отношение не нравится никому… Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
||||||
Hugo Пользователь Сообщений: 23249 |
#21 28.01.2017 11:50:10 Есть одна тонкость с
— Microsoft не обещает точное соответствие этих двух массивов, т.е. вываливать их рядом небезопасно. Изменено: Hugo — 28.01.2017 12:01:49 |
||
The_Prist Пользователь Сообщений: 14181 Профессиональная разработка приложений для MS Office |
Согласен с Игорем. Лучше создавать под это отдельный массив и в цикле выгружать туда сначала ключ, а потом соответствующий ключу элемент. Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы… |
Юрий М Модератор Сообщений: 60570 Контакты см. в профиле |
Не совсем по теме, но близко )) |
webley Пользователь Сообщений: 1991 |
Юрий М, очень пригодилось, спасибо! |
Alex_ST Пользователь Сообщений: 2746 На лицо ужасный, добрый внутри |
#25 01.07.2022 14:53:39
Что-то я этот совет Юрия либо пропустил, либо просто забыл… С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!) |
||
Jack Famous Пользователь Сообщений: 10846 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 Пользователь Сообщений: 10846 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 Пользователь Сообщений: 10846 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 Добрый вечер, Алексей. |
Содержание
- Объект Dictionary
- Синтаксис
- Замечания
- Методы
- Свойства
- См. также
- Поддержка и обратная связь
- Vba excel collection dictionary
- 2. Создание Dictionary
- 3. Свойства и методы объекта Dictionary
- 4. Наполнение словаря
- 4.1. Типы данных ключа и элемента
- 4.2. Через метод Add
- 4.3. Через свойство Item
- 4.4. Неявное добавление ключа в Dictionary
- 5. Удаление элементов
- VBA Dictionary
- Excel VBA Dictionary
- Working with VBA Dictionaries
- Create Instance of Dictionary with VBA Code
- Understanding KEY & ITEM
- Check Whether the Mobile Phone is there or not.
- Recommended Articles
Объект Dictionary
Объект, в котором хранятся пары «ключ-элемент» данных.
Синтаксис
Scripting.Dictionary
Замечания
Объект Dictionary является эквивалентом ассоциативного массива языка PERL. Элементы, представляющие собой любую форму данных, хранятся в массиве. Каждый элемент ассоциируется с уникальным ключом. Ключ используется для получения отдельного элемента и обычно представляет собой целое число или строку, но может быть любым, кроме массива.
В следующем коде показано, как создать объект Dictionary .
Методы
Метод | Описание |
---|---|
Добавление | Добавляет новую пару «ключ-элемент» в объект Dictionary . |
Exists | Возвращает логическое значение, указывающее, существует ли указанный ключ в объекте Dictionary . |
Items | Возвращает массив всех элементов объекта Dictionary . |
Keys | Возвращает массив всех ключей в объекте Dictionary . |
Remove | Удаляет одну указанную пару «ключ-элемент» из объекта Dictionary . |
RemoveAll | Удаляет все пары «ключ-элемент» в объекте Dictionary . |
Свойства
Свойство | Описание |
---|---|
CompareMode | Задает или возвращает режим сравнения для сравнения ключей в объекте Dictionary . |
Count | Возвращает количество пар «ключ-элемент» в объекте Dictionary . |
Элемент | Задает или возвращает значение элемента в объекте Dictionary . |
Ключ | Задает новое значение ключа для существующего значения ключа в объекте Dictionary . |
См. также
Поддержка и обратная связь
Есть вопросы или отзывы, касающиеся Office VBA или этой статьи? Руководство по другим способам получения поддержки и отправки отзывов см. в статье Поддержка Office VBA и обратная связь.
Источник
Vba excel collection dictionary
Если вы программируете на VBA/VBS, то рано или поздно вынуждены будете познакомиться с объектом Dictionary . Если в двух словах, то Dictionary — это продвинутый массив. Как вы знаете, массив — это упорядоченный набор неких (обычно однородных) элементов. Вот типичный массив:
Элементы пронумерованы и доступны по номеру индекса. Индекс всегда числовой.
А вот, что из себя представляет Dictionary (словарь):
Как видите, каждому элементу поставлен в соответствие не просто числовой индекс, а уникальный ключ, который в данном случае представляет из себя текстовую строку (имена). Двух одинаковых ключей в словаре быть не может, но могут быть одинаковые элементы (хоть все одинаковые). Таким образом словарь — это обычно некий список, снабжённый ключом, при помощи которого вы хотите извлекать полезную информацию (элементы). В указанном примере мы имеем, допустим, имена детей в качестве ключа, а в качестве элементов, поставленных в соответствие ключу, скажем, количество карманных денег у ребёнка.
С другой стороны нечто подобное можно же сделать, используя массив. Давайте объявим двумерный массив:
Должно быть у словаря есть какие-то преимущества перед таким использованием массивов? И это действительно так!
Давайте пока просто перечислим важнейшие преимущества:
Словарь контролирует уникальность ключей. Два одинаковых ключа не могут быть добавлены в словарь. Это важное свойство, так как программисту очень часто требуется обеспечить или проконтролировать уникальность каких-либо наборов значений, и в этом может с успехом быть использован Dictionary ;
Словарь очень эффективно (при помощи встроенного алгоритма бинарного поиска) осуществляет извлечение элементов по известному ключу. В десятки раз быстрее, чем обычный перебор;
У словаря есть встроенный метод ( Exists ), при помощи которого можно понять, добавлен ли некий ключ в коллекцию;
Словарь позволяет добавлять новые элементы и удалять любые элементы, что, работая с массивами, сделать гораздо сложнее;
Словарь может вернуть все ключи и все элементы в виде отдельных одномерных массивов.
2. Создание Dictionary
Существует несколько способов создать объект типа Dictionary . Ознакомимся с ними:
Считается, что методы, использующие позднее связывание надёжнее в плане обеспечения работоспособности программы на разных компьютерах, так как не зависят от настроек Tools — References. редактора VBA.
Однако, учитывая, что библиотека Microsoft Scripting Runtime присутствует везде, начиная с Windows 2000 , я думаю, что вы без какого-либо ущерба можете использовать методы раннего связывания. Раннее связывание хорошо тем, что оно несколько быстрее работает, а также во время разработки вы можете пользоваться функцией завершения кода (когда среда программирования вам подсказывает имеющиеся у объекта свойства и методы). Выбор за вами.
3. Свойства и методы объекта Dictionary
Тип | Идентификатор | Описание |
Свойство | Count | dicObject.Count Возвращает количество элементов в словаре. Только для чтения. |
Свойство | Item | dicObject.Item(key)[ = newitem] Устанавливает или возвращает элемент с указанным ключом. Чтение/запись. |
Свойство | Key | dicObject.Key(key) = newkey Заменяет ключ элемента на новое значение. |
Свойство | CompareMode | dicObject.CompareMode[ = compare] Устанавливает и возвращает режим сравнения текстовых ключей в словаре. Чтение/запись. |
Метод | Add | dicObject.Add (key, item) Добавляет пару ключ-элемент в словарь. |
Метод | Exists | dicObject.Exists(key) Возвращает true, если указанный ключ существует в словаре, либо false — в противном случае. |
Метод | Items | dicObject.Items( ) Возвращает массив, состоящий из всех элементов, имеющихся в коллекции. |
Метод | Keys | dicObject.Keys( ) Возвращает массив, состоящий из всех ключей, имеющихся в коллекции. |
Метод | Remove | dicObject.Remove(key) Удаляет из словаря элемент с указанным ключом. |
Метод | RemoveAll | dicObject.RemoveAll( ) Полностью очищает словарь от элементов. Сам объект словаря при этом не уничтожается. |
4. Наполнение словаря
4.1. Типы данных ключа и элемента
Dictionary наполняется по одному элементу. Не существует способов наполнить словарь массово. Чтобы добавить в словарь новый элемент вы должны иметь уникальный ключ и сам элемент, который под этим ключом будет храниться в словаре.
В качестве типа данных для элемента может быть использовано практически всё что угодно: числа, логический тип, строки (в том числе пустые), дата-время, массивы, любые объекты (листы, диапазоны, коллекции, другие словари, пустой указатель Nothing ).
В качестве типа данных для ключа могут быть использованы: числа, строки, дата-время, объекты, но не массивы.
UDT (User Defined Type) не может напрямую использоваться в качестве ключа и/или элемента, но данное ограничение можно обойти, объявив аналог UDT , создав класс и определив в нём свойства аналогичные имеющимся в UDT . А поскольку класс — это объектный тип, то его уже можно использовать для ключей и элементов.
4.2. Через метод Add
На листе Example , прилагаемого к статье файла, есть таблица с TOP30 стран по площади их территории. Для области данных этой таблицы объявлен именованный диапазон SquareByCountry . Пример ниже добавляет все строки указанногот ИД в Dictionary по принципу страна ( key ) — площадь ( item ):
Как видите, для добавления элемента (item) мы в 12-й строке кода использовали метод Add объекта dicCountry . Если в нашей таблице будет задвоена страна, то при попытке добавить в словарь элемента с ключом, который в словаре уже есть, будет сгенерировано исключение:
4.3. Через свойство Item
Используя свойство Item , также можно добавлять пары ключ-элемент, однако, при попытке добавить дублирующий ключ исключения сгенерировано НЕ БУДЕТ , а элемент будет заменён на новый (с потерей старого). Это очень полезно — иметь возможность выбирать способы наполнения словаря, отличающиеся реакцией на задвоение ключей.
4.4. Неявное добавление ключа в Dictionary
И ещё один неожиданный и я бы сказал экзотический способ пополнения словаря. Если упомянуть свойство Item по ПРАВУЮ сторону оператора присваивания, то он оказывается добавит в словарь key с пустым item, если данного key не существует в коллекции. Если же такой key уже существует, то никаких действий предпринято не будет.
Ещё раз хочу обратить ваше внимание, что элемент (item) при таком пополнении коллекции будет пустым ( Empty ). Это можно использовать, если вам нет необходимости что-то хранить в элементах в качестве полезной нагрузки (например, когда вы просто строите список уникальных значений, встречающихся в столбце таблицы).
Если вы читаете словарь через Item (а это, собственно, самый логичный и распространенный метод), и при этом хотите избежать добавления пустых ключей в словарь, используйте предварительно метод Exists , что контроля наличия такого ключа в коллекции.
5. Удаление элементов
Есть 2 варианта удаления элементов из словаря:
Источник
VBA Dictionary
Excel VBA Dictionary
Using VBA Dictionary, we can group all kinds of data in a dictionary to get access to all the items with a single variable. For example, we can use the Dictionary to create a collection of key-value combinations. Then, once the object links to keys, we can call them later by just using the key name.
VBA Dictionary is very tough to get inside, but we will try our best to make it easy for you to understand. We can compare both Dictionary and Collection on the same scale. Still, some of the VBA dictionaries offer some of the functionalities that are not available with the VBA Collections VBA Collections VBA Collection is an uncomplicated data structure used for storing/collecting objects. Unlike VBA Array, you can more conveniently add & remove the items here. read more object.
Table of contents
You are free to use this image on your website, templates, etc., Please provide us with an attribution link How to Provide Attribution? Article Link to be Hyperlinked
For eg:
Source: VBA Dictionary (wallstreetmojo.com)
Working with VBA Dictionaries
To work with VBA Dictionaries, we first need to set the object reference to ‘Microsoft Scripting Runtime.’
To set the reference, follow the below steps.
Step 1: Go to Tools > References.
Step 2: Scroll down, select the ‘Microsoft Scripting Runtime’ option, then click “OK.”
Now, we can access the VBA Dictionary with the Scripting Library.
Create Instance of Dictionary with VBA Code
After setting the reference to ‘Microsoft Scripting Runtime,’ we need to create an instance of the VBA Dictionary. First, declare the variable as Scripting.Dictionary.
Code:
Now, the variable “Dict” is an object variable. Therefore, we need to set the object reference for the object variable by using the word “New.”
Now, we can access all the properties and methods of the dictionary.
Note: All the green buttoned words are “Methods,” and others are “Properties.”
Now, declare one variable as “DictResult.”
We will create a new key using the “Dict” variable.
The Key is what the word we are adding is. So, let’s add the mobile phone name as “Redmi.”
Item is nothing but the definition of the word (key) we have added. This definition of the phone is its price so we will add the price to 15000.
Now, for another variable, “DictResult,” we will add a keyword using the “Dict” variable.
The Key is the word we have created in the previous step, the name of the phone.
Code:
Now, run the code manually or using the F5 key, and a message box will show you the price (item) of the phone (key) we have added using “Dict.”
Understanding KEY & ITEM
If you have not understood KEY and ITEM, let us explain with a simple example. Imagine a real-world dictionary. With this Dictionary, we have words (keys) and the meaning of those words (item). Similarly, words are “Keys,” and the definition or meaning is the “Item.”
Now, look at one more example of a Dictionary. Assume you are searching for a phone number of a particular person. How do you search?
Obviously, by using the name, we have used it while saving the phone number. So, here we have two things one is the Name of the Person and the second one is the Phone Number.
The name of the Person is Key.
The Phone Number is Item.
Check Whether the Mobile Phone is there or not.
Imagine giving your customers a user form to check the mobile phone’s price with a simple input box. Below Excel VBA code Excel VBA Code VBA code refers to a set of instructions written by the user in the Visual Basic Applications programming language on a Visual Basic Editor (VBE) to perform a specific task. read more will present an input box in front of the user, and they need to enter the brand of the phone they are looking for. If the brand name is in the Dictionary, it will show the price of the respective phone or display the message as “Phone You are Looking for Doesn’t Exist in the Library.”
Code:
Run this code using the F5 key or manually and see the result.
Recommended Articles
This article has been a guide to the VBA Dictionary. Here, we learn how to use VBA Dictionary to create a collection of key-value combinations in Excel with practical examples and a downloadable template. Below you can find some useful Excel VBA articles: –
Источник
Excel VBA Dictionary
Using VBA Dictionary, we can group all kinds of data in a dictionary to get access to all the items with a single variable. For example, we can use the Dictionary to create a collection of key-value combinations. Then, once the object links to keys, we can call them later by just using the key name.
VBA Dictionary is very tough to get inside, but we will try our best to make it easy for you to understand. We can compare both Dictionary and Collection on the same scale. Still, some of the VBA dictionaries offer some of the functionalities that are not available with the VBA CollectionsVBA Collection is an uncomplicated data structure used for storing/collecting objects. Unlike VBA Array, you can more conveniently add & remove the items here. read more object.
Table of contents
- Excel VBA Dictionary
- Working with VBA Dictionaries
- Create Instance of Dictionary with VBA Code
- Understanding KEY & ITEM
- Check Whether the Mobile Phone is there or not.
- Recommended Articles
Working with VBA Dictionaries
To work with VBA Dictionaries, we first need to set the object reference to ‘Microsoft Scripting Runtime.’
To set the reference, follow the below steps.
Step 1: Go to Tools > References.
Step 2: Scroll down, select the ‘Microsoft Scripting Runtime’ option, then click “OK.”
Now, we can access the VBA Dictionary with the Scripting Library.
You can download this VBA Dictionary Excel Template here – VBA Dictionary Excel Template
Create Instance of Dictionary with VBA Code
After setting the reference to ‘Microsoft Scripting Runtime,’ we need to create an instance of the VBA Dictionary. First, declare the variable as Scripting.Dictionary.
Code:
Sub Dict_Example1() Dim Dict As Scripting.Dictionary End Sub
Now, the variable “Dict” is an object variable. Therefore, we need to set the object reference for the object variable by using the word “New.”
Set Dict = New Scripting.Dictionary
Now, we can access all the properties and methods of the dictionary.
Note: All the green buttoned words are “Methods,” and others are “Properties.”
Now, declare one variable as “DictResult.”
Dim DictResult As Variant
We will create a new key using the “Dict” variable.
The Key is what the word we are adding is. So, let’s add the mobile phone name as “Redmi.”
Item is nothing but the definition of the word (key) we have added. This definition of the phone is its price so we will add the price to 15000.
Now, for another variable, “DictResult,” we will add a keyword using the “Dict” variable.
The Key is the word we have created in the previous step, the name of the phone.
Now, the variable “DictResult” has the item of the key we have added. Now show the result of the variable in the VBA message boxVBA MsgBox function is an output function which displays the generalized message provided by the developer. This statement has no arguments and the personalized messages in this function are written under the double quotes while for the values the variable reference is provided.read more.
Code:
Sub Dict_Example1() Dim Dict As Scripting.Dictionary Set Dict = New Scripting.Dictionary Dim DictResult As Variant Dict.Add Key:="Redmi", Item:=15000 DictResult = Dict("Redmi") MsgBox DictResult End Sub
Now, run the code manually or using the F5 key, and a message box will show you the price (item) of the phone (key) we have added using “Dict.”
Understanding KEY & ITEM
If you have not understood KEY and ITEM, let us explain with a simple example. Imagine a real-world dictionary. With this Dictionary, we have words (keys) and the meaning of those words (item). Similarly, words are “Keys,” and the definition or meaning is the “Item.”
Now, look at one more example of a Dictionary. Assume you are searching for a phone number of a particular person. How do you search?
Obviously, by using the name, we have used it while saving the phone number. So, here we have two things one is the Name of the Person and the second one is the Phone Number.
The name of the Person is Key.
The Phone Number is Item.
If you want the example of Excel, we can give VLOOKUP as an example. We use the formula to look for values based on the LOOKUP VALUE (Key). The result returned by the VLOOKUP functionThe VLOOKUP excel function searches for a particular value and returns a corresponding match based on a unique identifier. A unique identifier is uniquely associated with all the records of the database. For instance, employee ID, student roll number, customer contact number, seller email address, etc., are unique identifiers.
read more is called Item.
Check Whether the Mobile Phone is there or not.
Imagine giving your customers a user form to check the mobile phone’s price with a simple input box. Below Excel VBA codeVBA code refers to a set of instructions written by the user in the Visual Basic Applications programming language on a Visual Basic Editor (VBE) to perform a specific task.read more will present an input box in front of the user, and they need to enter the brand of the phone they are looking for. If the brand name is in the Dictionary, it will show the price of the respective phone or display the message as “Phone You are Looking for Doesn’t Exist in the Library.”
Code:
Sub Dict_Example2() Dim PhoneDict As Scripting.Dictionary Dim DictResult As Variant Set PhoneDict = New Scripting.Dictionary PhoneDict.Add Key:="Redmi", Item:=15000 PhoneDict.Add Key:="Samsung", Item:=25000 PhoneDict.Add Key:="Oppo", Item:=20000 PhoneDict.Add Key:="VIVO", Item:=21000 PhoneDict.Add Key:="Jio", Item:=2500 DictResult = Application.InputBox(Prompt:="Please Enter the Phone Name") If PhoneDict.Exists(DictResult) Then MsgBox "The Price of the Phone " & DictResult & " is : " & PhoneDict(DictResult) Else MsgBox "Phone You are Looking for Doesn't Exists in the Library" End If End Sub
Run this code using the F5 key or manually and see the result.
Recommended Articles
This article has been a guide to the VBA Dictionary. Here, we learn how to use VBA Dictionary to create a collection of key-value combinations in Excel with practical examples and a downloadable template. Below you can find some useful Excel VBA articles: –
- How to use ME in Excel VBA?
- Charts in VBA
- New Line in VBA MsgBox
- What is VBA Split Function in Excel?
Всё про коллекции в VBA
Автор Дмитрий Якушев На чтение24 мин. Просмотров1.8k.
Леонард Лаудер
Я не строитель зданий, я строитель коллекций
Содержание
- Краткое руководство по коллекциям
- Введение
- Что такое коллекция?
- Коллекции против Массивов
- Пример: когда Массив лучше
- Пример: когда Коллекция лучше
- Еще одно преимущество коллекций
- Недостаток коллекций
- Как создать коллекцию
- Незначительная разница между этими методами
- Удаление всех элементов из коллекции
- Добавление предметов в коллекцию
- Before и After
- Доступ к элементам коллекции
- Элементы в коллекции доступны только для чтения?
- Добавление разных типов
- Добавление элементов с помощью ключа
- Когда использовать ключи
- Недостаток использования ключей в коллекциях
- Доступ ко всем элементам в коллекции
- Использование цикла For
- Использование цикла For Each
- For Each против For
- Скорость
- Аккуратнее
- Порядок
- Сортировка коллекции
- Использование коллекций с функциями и подпрограммами
- Передача Коллекции в Sub / Function
- Передача ByVal против ByRef
- Возврат коллекции из функции
- Заключение
Краткое руководство по коллекциям
Задача |
Пример |
Объявить |
Dim coll As Collection |
Создать во время выполнения |
Set coll = New Collection |
Объявить и создать |
Dim coll As New Collection |
Добавить элемент |
|
Доступ к элементу |
coll(1) or coll(2) |
Элемент доступа добавлен в |
coll(1) |
Доступ к элементу добавлен в |
coll(coll.Count) |
Получить количество предметов |
coll.Count |
Доступ ко всем предметам |
Dim i As Long |
Доступ ко всем предметам (For |
Dim fruit As Variant |
Удалить элемент |
coll.Remove(1) |
Удалить все элементы |
Set coll = New Collection |
Введение
Коллекции являются очень важной частью VBA. Если вы пользовались VBA какое-то время, вы будете использовать Коллекции. Наиболее распространенными из них являются
Workbooks, Worksheets, коллекции Range и Cells.
В следующем коде показаны некоторые примеры использования коллекции Workbooks VBA.
1 2 3 4 5 6 7 8 9 10 |
‘ Workbooks это коллекция всех открытых рабочих книг ‘ Count — это количество книг в коллекции. Debug.Print Workbooks.Count ‘ Напечатайте полное имя книги с именем Пример.xlsm Debug.Print Workbooks(«Пример.xlsm»).FullName ‘ Напечатайте полное название книги, которая была открыта второй Debug.Print Workbooks(2).FullName |
Коллекции похожи на массивы, поэтому важно понимать, что они из себя представляют и чем они отличаются от массивов.
Что такое коллекция?
Коллекции и массивы используются для группировки переменных. Они оба хранят набор похожих предметов, например список студенческих оценок или названий стран. Использование коллекции или массива позволяет быстро и легко манипулировать большим количеством предметов.
В своей статье о массивах я объяснил простым языком, что такое массивы и почему они так полезны. Я кратко изложу эту информацию здесь.
Если вы сохраняете оценки одного ученика, вы можете легко сделать это, используя одну переменную.
1 2 |
Dim mark As Long mark = sheetMarks.Range(«A1») |
Однако в большинстве случаев вам придется иметь дело с несколькими студентами. Представьте, что вы хотите хранить оценки 100 учеников. Если вы не использовали коллекции или массивы, вам нужно было бы создать сотню переменных — одну переменную для хранения оценки для каждого учащегося.
Другая проблема заключается в том, что вы должны использовать эти переменные по отдельности. Если вы хотите сохранить 100 отметок, вам понадобится строка кода каждый раз, когда вы хотите сохранить значение в переменной.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
‘ Объявите переменную для каждой оценки Dim mark1 As Long Dim mark2 As Long . . . Dim mark100 As Long ‘ Сохраните отметки на листе в переменной mark1 = sheetMarks.Range(«A1») mark2 = sheetMarks.Range(«A2») . . . mark100 = sheetMarks.Range(«A100») |
Как вы можете видеть в приведенном выше примере, написание такого кода означало бы сотни строк повторяющегося кода. Когда вы используете коллекцию или массив, вам нужно только объявить одну переменную. Использование цикла с коллекцией или массивами означает, что вам нужна только одна строка для добавления или чтения значений.
Если мы переписываем приведенный выше пример с использованием коллекции, нам нужно всего несколько строк кода
1 2 3 4 5 6 7 8 9 |
‘ Создать коллекцию Dim collMarks As New Collection ‘ Прочитайте 100 значений в коллекцию Dim c As Range For Each c In Sheet1.Range(«A1:A100») ‘ Эта строка используется для добавления всех значений collMarks.Add c.Value Next |
Коллекции против Массивов
Мы рассмотрели, что общего у коллекций и массивов. Так в чем же разница и зачем использовать один вместо другого?
Основное отличие состоит в том, что с массивом вы обычно устанавливаете размер один раз. Это означает, что вы знаете размер до того, как начнете добавлять элементы. Позвольте мне объяснить это на примере.
Пример: когда Массив лучше
Представьте, что у вас есть лист оценок учеников с одним учеником на строку:
Вы хотите хранить информацию о каждом ученике. В этом примере вы можете легко посчитать количество строк, чтобы получить количество студентов. Другими словами, вы знаете количество предметов заранее.
1 2 3 4 5 6 7 |
‘ Получить последнюю строку — это количество студентов 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 неиспользуемых слотов массива.
Вы также можете изменить размер массива для каждого элемента по мере его добавления. Это очень неэффективно и довольно грязно.
Так что для этого примера лучше использовать коллекцию.
1 2 3 4 5 6 7 8 9 |
‘ Объявить Dim coll As New Collection ‘ Добавить элемент — VBA следит за изменением размера coll.Add «Яблоко» coll.Add «Слива» ‘ удалить элемент — VBA следит за изменением размера coll.Remove 1 |
Когда вы добавляете или удаляете элемент в коллекцию, VBA выполняет все изменения размера за вас. Вам не нужно указывать размер или выделять новые пробелы. VBA делает это самостоятельно. Все, что вам нужно сделать, это добавить элемент или удалить его.
Коллекция используется, когда размер часто изменяется.
Еще одно преимущество коллекций
Коллекции гораздо проще использовать, чем массивы, особенно если вы новичок в программировании. Большую часть времени вы делаете три вещи с коллекциями:
- Создать коллекцию
- Добавьте несколько предметов
- Прочитайте предмет
Так что, если вы не имеете дело с большим количеством предметов, тогда использование Коллекции может быть намного удобнее в использовании.
Недостаток коллекций
Основные типы данных (т.е. переменные, такие как string, date, long, currency и т.д.) в коллекциях доступны только для чтения. Вы можете добавить или удалить элемент, но не можете изменить его значение. Если вы собираетесь изменять значения в группе элементов, вам нужно будет использовать массив.
Если вы храните объект в коллекции, вы можете изменить значение, так как коллекция хранит ссылку, а не фактический объект.
Коллекция только для чтения
Теперь, когда мы знаем, когда и зачем использовать коллекцию, давайте посмотрим, как ее использовать.
Как создать коллекцию
Вы можете объявить и создать в одной строке, как это делает следующий код:
1 2 |
‘ Объявить и создать Dim coll As New Collection |
Как видите, вам не нужно указывать размер. После того, как ваша коллекция создана, вы можете легко добавлять в нее элементы.
Вы также можете объявить и затем создать коллекцию, если и когда вам это нужно.
1 2 3 4 5 |
‘ Объявить Dim coll As Collection ‘ Создать Коллекцию Set coll = New Collection |
Незначительная разница между этими методами
Разница между этими методами заключается в том, что для первого всегда создается коллекция. Для второго метода коллекция создается только при достижении строки Set. Таким образом, вы можете установить код для создания коллекции только при соблюдении определенного условия.
1 2 3 4 5 6 7 |
‘ Объявить Dim coll As Collection ‘ Создать коллекцию, если файл найден If filefound = True Then Set coll = New Collection Endif |
Преимущество использования этого метода минимально. Выделение памяти было важно еще в 1990-х годах, когда память компьютера была ограничена. Если вы не создаете огромное количество коллекций на медленном ПК, вы никогда не заметите никакой выгоды.
Использование Set означает, что коллекция будет вести себя иначе, чем когда вы устанавливаете коллекцию в ничто. Следующий раздел объясняет это.
Удаление всех элементов из коллекции
Коллекция не имеет функции RemoveAll. Однако, чтобы удалить все элементы из коллекции, вы можете просто установить ее в новую коллекцию.
1 |
Set Coll = New Collection. |
VBA удалит коллекцию, потому что мы больше не ссылаемся на нее. Когда мы удаляем все предметы, мы обычно хотим использовать коллекцию снова, поэтому мы эффективно убиваем двух зайцев одним выстрелом, используя этот метод.
1 2 3 4 5 6 7 8 9 10 11 |
Sub UdalitKollekciyu() Dim coll1 As New Collection coll1.Add «яблоко» coll1.Add «слива» ‘ Оригинальная коллекция удалена Set coll1 = New Collection End Sub |
Следует помнить одну тонкую вещь: если у нас есть две или более переменных, которые ссылаются на одну и ту же коллекцию, она не будет удалена (см. Очистка памяти в VBA).
В приведенном ниже примере исходные элементы коллекции не удаляются, так как он все еще является ссылкой по coll2.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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, за которым следует значение, которое вы хотите добавить.
1 2 |
collFruit.Add «Яблоко» collFruit.Add «Слива» |
Вы можете иметь любой базовый тип в коллекции, например, Double
1 2 |
collTotals.Add 45.67 collTotals.Add 34.67 |
Когда вы добавляете элементы таким способом, они добавляются в следующий доступный индекс. В примере с фруктами яблоко добавляется в положение 1, а слива — в положение 2.
Before и After
Вы можете использовать параметры «Before» или «After», чтобы указать, где вы хотите разместить элемент в коллекции. Обратите внимание, что вы не можете использовать оба этих аргумента одновременно.
1 2 3 4 |
collFruit.Add «Яблоко» collFruit.Add «Слива» ‘ Добавить лимон перед первым пунктом collFruit.Add «Лимон», Before:=1 |
После этого кода порядок коллекции выглядит так:
- Лимон
- Яблоко
- Слива
1 2 3 4 |
collFruit.Add «Яблоко» collFruit.Add «Слива» ‘ Добавьте лимон после первого пункта collFruit.Add «Лимон», After:=1 |
После этого кода порядок коллекции выглядит так:
- Яблоко
- Лимон
- Слива
Доступ к элементам коллекции
Для доступа к элементам коллекции вы просто используете индекс. Как мы увидели, индекс — это позиция элемента в коллекции на основе порядка, в котором они были добавлены.
Порядок также можно установить с помощью параметра «Before» или «After».
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
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 |
Вы также можете использовать свойство элемента для доступа к элементу в коллекции. Это метод по умолчанию для коллекции, поэтому следующие строки кода эквивалентны.
1 2 |
Debug.Print coll(1) Debug.Print coll.Item(1) |
Элементы в коллекции доступны только для чтения?
Это очень важный момент. Когда базовый тип данных хранится в коллекции, он доступен только для чтения. Базовый тип данных — это строка, дата, целое число, длина и т.д.
Если вы попытаетесь обновить элемент коллекции, вы получите сообщение об ошибке. Следующий код выдает ошибку «Требуется объект».
1 2 3 4 5 6 7 8 9 10 |
Sub NapisatZnachenie() Dim coll As New Collection coll.Add «Яблоко» ‘ Эта строка вызывает ОШИБКУ coll(1) = «Слива» End Sub |
Вы можете изменить объект, который хранится в коллекции
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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 на самом деле доступна только для чтения, но объект, на который она указывает, — нет.
Все, что вам нужно помнить, это то, что базовые типы данных в коллекции доступны только для чтения. Объекты в коллекции могут быть изменены.
Вы можете прочитать больше об объектах в памяти здесь.
Добавление разных типов
Вы также можете добавлять различные типы предметов в коллекцию.
1 2 3 |
collFruit.Add «Яблоко» collFruit.Add 45 collFruit.Add #12/12/2019# |
Это редко нужно. В VBA коллекции Sheets содержат листы типа Worksheet и типа Chart. (Чтобы создать лист с диаграммой, просто щелкните правой кнопкой мыши любую диаграмму, выберите «Переместить» и установите переключатель «Новый лист»).
Следующий код отображает тип и имя всех листов в текущей книге. Обратите внимание, что для доступа к другому типу необходимо, чтобы переменная For Each была вариантом, иначе вы получите ошибку.
1 2 3 4 5 6 7 8 9 |
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.
Редко вам понадобится коллекция разных типов, но, как видите, иногда это может быть полезно.
Добавление элементов с помощью ключа
Вы также можете добавить элементы, используя ключ, как показано в следующем примере:
1 2 3 |
collMark.Add Item:=45, Key:=»Петр» Debug.Print «Оценки Петра: «,collMark(«Петр») |
Я включил имена параметров, чтобы сделать приведенный выше пример понятным. Однако вам не нужно этого делать. Просто помните, что ключ является вторым параметром и должен быть уникальной строкой.
Следующий код показывает второй пример использования ключей.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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 доступ к рабочей книге гораздо лучше по ключу (имени), чем по индексу. Порядок зависит от порядка, в котором они были открыты, и поэтому является довольно случайным.
1 2 3 4 5 6 7 |
Sub IspolzovanieWorkbook() Debug.Print Workbooks(«Пример.xlsm»).Name Debug.Print Workbooks(1).Name End Sub |
Когда использовать ключи
Пример использования ключей: представьте, что у вас есть набор идентификаторов для 10 000 учащихся вместе с их оценками.
У вас также есть несколько отчетов на листе, которые содержат списки идентификаторов студентов. Для каждого из этих рабочих листов вам необходимо распечатать отметку для каждого учащегося.
Вы можете сделать это, добавив 10 000 студентов в коллекцию, используя их идентификатор в качестве ключа. Когда вы читаете удостоверение личности с листа, вы можете получить прямой доступ к оценкам этого студента.
Если вы не используете ключ, вам придется искать по 10 000 идентификаторов для каждого идентификатора в отчете.
Недостаток использования ключей в коллекциях
В коллекциях есть два недостатка ключей
- Вы не можете проверить, существует ли Ключ.
- Вы не можете обновить значение, хранящееся в ключе
Первый вопрос легко обойти. Следующий код проверяет, существует ли ключ.
1 2 3 4 5 6 7 8 9 |
Function Exists(coll As Collection, key As String) As Boolean On Error Goto EH coll.Item key Exists = True EH: End Function |
Вы можете использовать это так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
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 вы используете индекс для доступа к каждому элементу. В следующем примере выводится имя всех открытых рабочих книг.
1 2 3 4 5 6 7 8 |
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 коллекции.
В следующем примере распечатываются все элементы в пользовательской коллекции.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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, который является специализированным циклом, используется для коллекций. Он не использует индекс, а формат показан в следующем примере.
1 2 3 4 5 6 7 8 |
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
В следующем примере показаны циклы для приведенного выше примера пользовательской коллекции.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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 аккуратнее писать, особенно если вы используете вложенные циклы. Сравните следующие циклы. Оба печатают названия всех рабочих листов в открытых рабочих книгах.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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 можно изменить. Вы можете прочитать предметы в обратном порядке. Вы можете прочитать раздел предметов или вы можете прочитать каждый второй элемент.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
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 |
Вы можете использовать это так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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
Это просто передать коллекцию в функцию или подпункт. Она передается как любой параметр, как показано в следующем примере кода.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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, значение изменилось в вызывающей процедуре.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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 в следующем примере удалят первый элемент из исходной коллекции.
1 2 3 4 5 6 7 |
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 не изменит оригинальную коллекцию
1 2 3 4 5 6 7 8 9 |
‘ Очистит исходную коллекцию Sub PassByRef(ByRef coll As Collection) Set coll = Nothing End Sub ‘ Не изменит исходную коллекцию Sub PassByVal(ByVal coll As Collection) Set coll = Nothing End Sub |
Возврат коллекции из функции
Возврат коллекции из функции — это то же самое, что вернуть любой объект. Вам нужно использовать ключевое слово Set. В следующем примере вы увидите, как вернуть коллекцию.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
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 более эффективен, но позволяет просматривать коллекцию только в одном порядке.
- Вы можете легко передать коллекцию в качестве аргумента в функцию или подпрограмму.
- Вы можете легко вернуть коллекцию из функции.
Источник