Excel vba collection dictionary

“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"

VBA Dictionary Fruit

Example of Key, Value pairs

In both cases, we are storing the value 5 and giving it the name “Apple”. We can now get the value of Apple from both types like this

' Get value from Dictionary
Total = dict("Apple")

' Get value from Collection
Total = coll("Apple")

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

  1. We cannot check if the key already exists.
  2. We cannot change the value of an existing item.

The first issue is pretty easy to get around: Check Collection Key exists. The second is more difficult.

The VBA Dictionary does not have these issues. You can check if a Key exists and you can change the Item 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

  1. Adds three fruit types and a value for each to a Dictionary.
  2. The user is asked to enter the name of a fruit.
  3. The code checks if this fruit is in the Dictionary.
  4. If yes then it displays the fruit name and the value.
  5. If no then it informs the user the fruit does not exist.
' 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.

  1. Select Tools->References from the Visual Basic menu.
  2. Find Microsoft Scripting Runtime in the list and place a check in the box beside it.

We declare a dictionary as follows

Dim dict As New Scripting.Dictionary

or

Dim dict As Scripting.Dictionary
Set dict = New Scripting.Dictionary

Creating a Dictionary 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

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

(*Intellisense is the feature that shows you the available procedures and properties of an item as you are typing.)

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

Error 457

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:

  1. Count – returns the number of items in the Dictionary.
  2. Remove – removes a given key from the Dictionary.
  3. RemoveAll – removes all items from the Dictionary

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

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

VBA Dictionary Key

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

VBA World Cup

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.

VBA Dictionary World Cup

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

VBA 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:

  1. WriteToImmediate prints the contents of the dictionary to the Immediate Window.
  2. WriteToWorksheet writes the contents of the dictionary to the worksheet called Output.

To run this example:

  1. Create a worksheet called Customers.
  2. Add the above data to the worksheet starting at cell A1.
  3. Create a worksheet called Output and leave it blank.
  4. Go to the Visual Basic Editor(Alt + F11).
  5. Select Tools->Reference and then check “Microsoft Scripting Runtime” from the list.
  6. Create a new class module and add the first piece of code from below.
  7. Create a new standard module and add the second piece of code from below.
  8. Press F5 to run and select Main from the menu.
  9. 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:

  1. You have a list of unique items e.g. countries, invoice numbers, customer name and addresses, project ids, product names etc.
  2. You need to retrieve the value of a unique item.

VBA Dictionary 1

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
Регистрация: 01.01.1970

Здравствуйте.

Расскажите или укажите, есть ли где сравнительное сопоставление трех понятий: массив, коллекция, словарь.
Хочу понять, когда и зачем их лучше использовать, в чем общее, в чем различие.

Изменено: borro26.01.2017 02:14:53

 

The_Prist

Пользователь

Сообщений: 14181
Регистрация: 15.09.2012

Профессиональная разработка приложений для MS Office

Общее: по сути это все массивы.
Различия: дофига. У коллекций свой набор методов, у словарей свой. У массивов в чистом виде по большому счету нет ничего. Но применимо к VBA чисто массив — arr() — можно заполнить очень быстро без цикла значением диапазона ячеек или формулами. Словари и коллекции требуют обязательного цикла для добавления элементов.
Преимущество коллекций(New Collection) — могут использоваться и в Windows и в MAC. А словари — только в Windows. Так же при добавлении элемента в коллекцию можно указать куда поместить новый элемент: до или после. Это дает возможность делать быструю сортировку уникальных значений.
Преимущество словарей: есть проверка наличия ключа встроенным свойством(Exists), что позволяет работать с ними быстрее. Так же можно настроить методы сравнения текста через свойство CompareMode. Если установить как 1 — то регистр не будет учитываться методом Exists при сравнении имеющихся в словаре элементов.

Но однозначно сказать что лучше, а что хуже нельзя. Все зависит от ситуации.

P.S. Не забывайте отписывать в своих темах, в которых получили ответы:

http://www.planetaexcel.ru/forum/index.php?PAGE_NAME=message&FID=1&TID=86715&TITLE_SEO=86715-kak-pol…
http://www.planetaexcel.ru/forum/index.php?PAGE_NAME=message&FID=1&TID=87222&TITLE_SEO=87222-ne-udae…

Иначе есть шанс потом ответы не получить…

Изменено: The_Prist25.01.2017 17:22:26

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

 

borro

Пользователь

Сообщений: 198
Регистрация: 01.01.1970

 

borro

Пользователь

Сообщений: 198
Регистрация: 01.01.1970

Например, в некотором цикле будут собираться данные вида:
Артикул1 Наименование1 число1 число2 … число15
Артикул1 Наименование1 другоечисло1 другоечисло2 … другоечисло15
Артикул2 Наименование1 число1 число2 … число15
Артикул2 Наименование2 число1 число2 … число15

Используя язык баз данных, пара значений «Артикул» и «Наименование» являются ключом для каждой строки массива данных.
На каждой итерации получения строки данных надо в некий тип данных(массив, коллекция, словарь) вносить получаемые значения таким образом:
1. если в хранилище нет пары с ключом артикул+наименование, то надо в него вносить получаемую строку
2. если уникальная пара уже есть в хранилище, то надо к хранящимся числовым значениям прибавить числовые значения новой строки, используя данные об артикуле и наименовании

Вопрос — в данной задаче надо использовать какой из типов данных?

 

Alex_ST

Пользователь

Сообщений: 2746
Регистрация: 22.12.2012

На лицо ужасный, добрый внутри

С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!)
<#0>

 

Alex_ST

Пользователь

Сообщений: 2746
Регистрация: 22.12.2012

На лицо ужасный, добрый внутри

ОГРОМНЫМ плюсом словарей является наличие в них методов Items и Keys возвращающих «одним махом» массивы ЗНАЧЕНИЙ и КЛЮЧЕЙ словаря
Да и вообще, у коллекций всего 1 свойство (.Count) и 4 метода (.Add .Item .Remove .Clear), а у словарей 4 свойства (.CompareMode .Count  .Item .Key) и 6 методов (.Add .Exists .Items .Keys .Remove .RemoveAll), что придаёт работе с ними значительно большую гибкость.
По приведённой выше ссылке я выкладывал файл-шпаргалку со свойствами, методами и примерами работы со словарями.

С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!)
<#0>

 

Alex_ST

Пользователь

Сообщений: 2746
Регистрация: 22.12.2012

На лицо ужасный, добрый внутри

#7

26.01.2017 16:15:31

Цитата
borro написал:
Артикул1 Наименование1 число1 число2 … число15
Артикул1 Наименование1 другоечисло1 другоечисло2 … другоечисло15
Артикул2 Наименование1 число1 число2 … число15
Артикул2 Наименование2 число1 число2 … число15

Так что уникальное? Похоже, что Артикул?
Ну и используйте их как ключи к значениям (записям) словаря. А в каждой записи могут лежать как массивы, так и подчинённые словари.
Там по ссылке есть пример использования словаря словарей.
Добавление ключа с пустой записью происходит автоматически при попытке обращения к словарю по отсутствующему ключу.
Единственный минус словарей по сравнению с коллекциями — это отсутствие у метода .Add опциональных параметров [Before | After], которые позволяют достаточно просто производить сортировку записей внутри коллекции.
Но это нужно, имхо, достаточно редко.

С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!)
<#0>

 

Sanja

Пользователь

Сообщений: 14838
Регистрация: 10.01.2013

#8

26.01.2017 16:30:00

Цитата
Alex_ST написал: Так что уникальное? Похоже, что Артикул?

Совсем не похоже.

Цитата
borro написал: Используя язык баз данных, пара значений «Артикул» и «Наименование» являются ключом для каждой строки массива данных

Уникальна ПАРА (Артикул и Наименование), поэтому в данном случае лучше использовать составной ключ (Артикул&Наименование)

Согласие есть продукт при полном непротивлении сторон.

 

Андрей VG

Пользователь

Сообщений: 11878
Регистрация: 22.12.2012

Excel 2016, 365

#9

26.01.2017 16:41:08

Доброе время суток.
Со словарями есть один не приятный момент, столкнулся случайно. Если выполнить

Код
Dictionary.RemoveAll
Set Dictionary = Nothing

, то это не приводит к автоматическому освобождению объектов-значений словаря. Они как-бы существуют вплодь до принудительного End, даже не до завершения метода, в котором создавался словарь. С коллекциями такого не происходит.

 

Alex_ST

Пользователь

Сообщений: 2746
Регистрация: 22.12.2012

На лицо ужасный, добрый внутри

#10

26.01.2017 16:47:34

Как-то я никогда особо освобождением памяти не заморачивался, хотя словари люблю и использую часто…
Обычно использую не явное позднее связывание типа

Код
With CreateObject("Scripting.Dictionary"): .CompareMode = vbTextCompare   ' создаем временный словарь
…
End With

Никогда никаких проблем не возникало. Может быть, при таком связывании их просто нет?
Или просто задачи не настолько тяжёлые, чтобы память ощутимо отожрать?

Изменено: Alex_ST26.01.2017 16:48:01

С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!)
<#0>

 

Андрей VG

Пользователь

Сообщений: 11878
Регистрация: 22.12.2012

Excel 2016, 365

Алексей, дело не в памяти — её хватало. А вот блокировка объектов не снималась. Пришлось делать вариант на Collection. Столкнулся не в Excel — в VBA IBM Rational System Architect.

Изменено: Андрей VG26.01.2017 16:52:58

 

Hugo

Пользователь

Сообщений: 23249
Регистрация: 22.12.2012

#12

26.01.2017 20:36:52

Цитата
borro написал:
Вопрос — в данной задаче надо использовать какой из типов данных?

— словарь для ключей с индексами, и массив для данных. Массив можно использовать тот же исходный.

 

SuperCat

Пользователь

Сообщений: 2737
Регистрация: 21.12.2012

#13

26.01.2017 21:38:36

Цитата
Андрей VG написал:
то это не приводит к автоматическому освобождению объектов-значений словаря

Интересно, а как это узнали?

There is no knowledge that is not power

 

Sanja

Пользователь

Сообщений: 14838
Регистрация: 10.01.2013

#14

26.01.2017 21:44:11

Цитата
Андрей VG написал: А вот блокировка объектов не снималась

Я вот тоже буквально сегодня заметил нечто подобное. Если

для словаря используется раннее связывание

словарь объявляется переменной (Dim dic1: Set dic1 = CreateObject(«Scripting.Dictionary»)), то наблюдаются какие-то глюки при попытке добавить НЕ уникальный ключ. С конструкцией With CreateObject(«Scripting.Dictionary») такого не происходит

Изменено: Sanja26.01.2017 22:12:25

Согласие есть продукт при полном непротивлении сторон.

 

The_Prist

Пользователь

Сообщений: 14181
Регистрация: 15.09.2012

Профессиональная разработка приложений для MS Office

#15

26.01.2017 21:49:52

Цитата
Sanja написал:
используется раннее связывание (Dim dic1: Set dic1 = CreateObject(«Scripting.Dictionary»)

Сёма, это-таки позднее связывание :) Раннее будет так:

Код
Dim dic1: Set dic1 = New Scripting.Dictionary

А при случае использования With очищение памяти от объектов происходит более корректно, когда-то мы вроде это обсуждали уже. Это касается не только словарей, кстати.  

Изменено: The_Prist26.01.2017 21:51:49

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

 

Sanja

Пользователь

Сообщений: 14838
Регистрация: 10.01.2013

Ага, Семёёён Семёёёныч  :). Но факт наблюдался

Согласие есть продукт при полном непротивлении сторон.

 

Alex_ST

Пользователь

Сообщений: 2746
Регистрация: 22.12.2012

На лицо ужасный, добрый внутри

#17

26.01.2017 22:09:30

Цитата
The_Prist написал: Не забывайте отписывать в своих темах…

Похоже, что Дмитрий у нас провидец…
borro заварил кашу и исчез. А мы тут его о чём-то спрашиваем, что-то советуем, дискуссию о высоких материях ведём…

С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!)
<#0>

 

Андрей VG

Пользователь

Сообщений: 11878
Регистрация: 22.12.2012

Excel 2016, 365

#18

26.01.2017 22:13:49

Цитата
SuperCat написал: Интересно, а как это узнали?

Да есть в этом RSA возможность делать перекрёстную связь между объектами. Пользователь добавляет ссылку с родительского объекта на дочерний и у дочернего появляется в свойствах ссылка на родительский. Соответственно, в VBA нужно ссылки добавлять только с одной стороны, иначе, так как объекты (родительский и дочерний) при их создании открыты на редактирование, то невозможно сохранить не тот не другой. При загрузке же данных описание связей идёт как попало. Вот я и сделал поиск родительского объекта для дочерних через словарь. Сохранил родительские, очистил словарь. Стал сохранять дочерние с установленными ссылками на родительские, а RSA выбрасывает объект заблокирован. Переделал на коллекции — ушло.

 

borro

Пользователь

Сообщений: 198
Регистрация: 01.01.1970

Доброго утра. Спасибо,

Sanja

за совет.
Дело в том, что остальные обсуждения моего последнего вопроса не касались, поэтому я молчал. Да и что отвечать, тут только впитывать информацию. Простите, если что не так :)

Изменено: borro28.01.2017 10:14:27

 

The_Prist

Пользователь

Сообщений: 14181
Регистрация: 15.09.2012

Профессиональная разработка приложений для MS Office

#20

28.01.2017 11:19:13

Цитата
borro написал:
Дело в том, что остальные обсуждения моего последнего вопроса не касались

А вопрос был какой последний?

Цитата
borro написал:
Вопрос — в данной задаче надо использовать какой из типов данных?

Вы все же получили после этого ответ от Alex_ST — словари.

Цитата
Alex_ST написал:
Посмотрите в топике  Dictionary — это совсем не сложно!

Но отписаться понятно-непонятно, оно-не оно уже не посчитали нужным. А между тем это проявление элементарной вежливости и уважения к отвечающим — отписаться ответившему: помогло — не помогло, понятно — не понятно и т.п. Чтобы все понимали имеет ли смысл дальше что-то предлагать или обсуждать. Т.к. Вы этого не делаете — тема развивается своим ходом, а Вас берут на заметку — типа это тот человек, который темы создает, ответы получает и сваливает. В результате что будет? Правильно. Вам просто перестанут отвечать, ибо потребительское отношение не нравится никому…

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

 

Hugo

Пользователь

Сообщений: 23249
Регистрация: 22.12.2012

#21

28.01.2017 11:50:10

Есть одна тонкость с

Цитата
Alex_ST написал:
ОГРОМНЫМ плюсом словарей является наличие в них методов Items и Keys возвращающих «одним махом» массивы ЗНАЧЕНИЙ и КЛЮЧЕЙ словаря

— Microsoft не обещает точное соответствие этих двух массивов, т.е. вываливать их рядом небезопасно.
В ответственных задачах нужно к каждому ключу получать значение в индивидуальном порядке. Да и transpose на больших объёмах может сглючить…

Изменено: Hugo28.01.2017 12:01:49
(буковка потерялась…)

 

The_Prist

Пользователь

Сообщений: 14181
Регистрация: 15.09.2012

Профессиональная разработка приложений для MS Office

Согласен с Игорем. Лучше создавать под это отдельный массив и в цикле выгружать туда сначала ключ, а потом соответствующий ключу элемент.

Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы…

 

Юрий М

Модератор

Сообщений: 60570
Регистрация: 14.09.2012

Контакты см. в профиле

Не совсем по теме, но близко ))
Недавно столкнулся с тем, что перебор коллекции циклом работает очень медленно: раньше приходилось обрабаывать относительно небольшие по размеру коллекции, а тут попалась довольно большая. Так вот: уже после 1000-го элемента коллекции увидел, что процесс «не летает» )) А нужно было перебрать порядка 30 000 элементов. ZVI подсказал, что не следует перебирать коллекции по индексу (For i = 1 to Коллекция.Count) — скорость нелинейно падает. Для перебора коллекции следует использовать цикл For Each — Next. Переделал — перемена поразительна!
Лично я этого не знал — может кому ещё пригодится )

 

webley

Пользователь

Сообщений: 1991
Регистрация: 01.01.1970

Юрий М, очень пригодилось, спасибо!
Единственно от себя дабавлю — это также справедливо и для словарей. Вложенный цикл по двум словарям (для каждого элемента первого перебирались все элементы второго, 3000 и 1500 элементов соответственно) — for j=0 to count просто «умер», после замены на for each — даже не заметно на фоне остальных операций

 

Alex_ST

Пользователь

Сообщений: 2746
Регистрация: 22.12.2012

На лицо ужасный, добрый внутри

#25

01.07.2022 14:53:39

Цитата
Юрий М написал:
Лично я этого не знал — может кому ещё пригодится )

Что-то я этот совет Юрия либо пропустил, либо просто забыл…
Сейчас практически не программирую. Но несколько лет назад всё равно почему-то предпочитал в своих разработках применять циклы For Each — Next. Наверное, интуитивно  :)

С уважением, Алексей (ИМХО: Excel-2003 — THE BEST!!!)
<#0>

 

Jack Famous

Пользователь

Сообщений: 10846
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#26

01.07.2022 17:10:51

Цитата
Alex_ST: почему-то предпочитал в своих разработках применять циклы For Each — Next

они надёжнее, позволяют собирать новый или изменять текущий массив по имеющемуся в цикле индексу. Например, цикл по тысячам областей (фильтр столбца по видимым) нельзя делать через For Each, потому что будет ошибка.

Честно говоря, есть сомнения по поводу скорости перебора словаря (коллекции не использую). Может, при позднем подключении, если только (я раннее использую). Тестов не вижу))

Изменено: Jack Famous01.07.2022 17:12:13

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

Jack Famous

Пользователь

Сообщений: 10846
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#27

01.07.2022 17:31:22

Действительно, перебор по индексам «в лоб» — не для словарей.
Не понимаю, зачем это может быть нужно, но, если всё-таки нужно, то взять массивы из словаря и перебирать их будет многократно (на примере — в 8 раз для 100 тыс ключей) быстрее

Файл и Код

При раннем связывании, разница в соответствии «ключ-значение» в массивах при их получении из словаря, не замечена. При позднем — я не уверен.
При этом ПОРЯДОК РАСПОЛОЖЕНИЯ ПАР элементов в словаре, вполне может не соответствовать их ПОРЯДКУ при НАПОЛНЕНИИ словаря

Что я имею в виду

Ссылки по теме:

bedvit про порядок ключей-значений
Словарь (Scripting.Dictionary). Соответствие массивов ключей и элементов между собой
Получить значение по ключу. Массив, Словарь и Коллекция, Get Item by Key. Array vs Dictionary vs Collection

Изменено: Jack Famous04.07.2022 09:37:34

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

ZVI

Пользователь

Сообщений: 4328
Регистрация: 23.12.2012

#28

02.07.2022 14:57:49

Цитата
Jack Famous написал: ‘dic.Keys(i) вообще не факт что равен arr(i)

Добрый день, Алексей.
Вы же сами в коде создали ключи словаря, начиная с нулевого, а не с первого, как в значении начального элемента массива.
В массиве точно так же значения массива, не совпадают с индексом массива: arr(0) <> 0
Это ошибка в представлении о логике кода, а не проблема словаря.
Код должен быть, например таким:

Код
Sub t()
  Dim dic As New Dictionary
  Dim arr(), i&
  arr = Array(0, 1, 2, 3, 4)
  For i = LBound(arr) To UBound(arr)
    dic(i) = "Item " & i
    Debug.Print dic.Keys(i) = arr(i), dic.Keys(i), arr(i)
  Next
End Sub
' Или таким
Sub t1()
  Dim dic As New Dictionary
  Dim arr(), i&
  arr = Array(1, 2, 3, 4, 5)
  For i = LBound(arr) To UBound(arr)
    dic(arr(i)) = "Item " & i
    Debug.Print dic.Keys(i) = arr(i), dic.Keys(i), arr(i)
  Next
End Sub

Цитата
Jack Famous написал: При этом ПОРЯДОК РАСПОЛОЖЕНИЯ ПАР элементов в словаре, вполне может не соответствовать их ПОРЯДКУ при НАПОЛНЕНИИ словаря

Это утверждение некорректное, так как касается внутреннего механизма работы словаря, а не его документированного внешнего интерфейса (свойств и методов .Item, .Keys, .Values и др.)
Словари всегда обеспечивают соответствие в массивах .Keys и .Values порядку заполнения словаря.
В словаре всегда доступ по ключу соответствует доступу по индексу.
Об этом мы в теме по Вашей 2-й ссылке уже общались —

здесь

.

Изменено: ZVI02.07.2022 15:40:30

 

Jack Famous

Пользователь

Сообщений: 10846
Регистрация: 07.11.2014

OS: Win 8.1 Корп. x64 | Excel 2016 x64: | Browser: Chrome

#29

04.07.2022 09:36:47

ZVI, приветствую! Всегда рад видеть вас в своих (и не только) темах  :idea:

Цитата
ZVI: Вы же сами в коде создали ключи словаря, начиная с нулевого, а не с первого, как в значении начального элемента массива

спасибо, согласен, оплошал, поправил  :)

Цитата
ZVI: Словари всегда обеспечивают соответствие в массивах .Keys и .Values порядку заполнения словаря … уже общались

там были только тесты, а хотелось бы увидеть документальное подтверждение, ведь никакими тестами нельзя доказать правило, а можно только приближаться к нему. А вот когда в докУменте будет написано — другое дело. Во всяком случае, логика Виталия мне понятна: они сказали, что это аналог перловых таблиц, у перловых таблиц порядок сбора и хранения не соответствует, а значит и у словарей тоже.
Тестами пытался повторить, но не вышло — пока что всегда соответствует  :D

Изменено: Jack Famous04.07.2022 09:38:07

Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄

 

ZVI

Пользователь

Сообщений: 4328
Регистрация: 23.12.2012

#30

04.07.2022 22:28:09

Добрый вечер, Алексей.
Гипотеза — это предположение для объяснения каких-то явлений. Но явлений-то в данном случае и нет.
Слова Виталия, в принципе, могут касаться только внутреннего устройства словаря, а не его внешнего интерфейса (см. моё сообщение выше).
Но т.к. и Вы, и Виталий на форуме — авторитеты, то подобное утверждение про словари запросто может кого-то ввести в заблуждение. Чего не хотелось бы. Собственно, поэтому и подключаюсь в тему.

Содержание

  1. Объект Dictionary
  2. Синтаксис
  3. Замечания
  4. Методы
  5. Свойства
  6. См. также
  7. Поддержка и обратная связь
  8. Vba excel collection dictionary
  9. 2. Создание Dictionary
  10. 3. Свойства и методы объекта Dictionary
  11. 4. Наполнение словаря
  12. 4.1. Типы данных ключа и элемента
  13. 4.2. Через метод Add
  14. 4.3. Через свойство Item
  15. 4.4. Неявное добавление ключа в Dictionary
  16. 5. Удаление элементов
  17. VBA Dictionary
  18. Excel VBA Dictionary
  19. Working with VBA Dictionaries
  20. Create Instance of Dictionary with VBA Code
  21. Understanding KEY & ITEM
  22. Check Whether the Mobile Phone is there or not.
  23. 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

VBA Dictionary

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.

VBA Dictionary step 1

Step 2: Scroll down, select the ‘Microsoft Scripting Runtime’ option, then click “OK.”

VBA Dictionary step 2

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

VBA Dictionary Example 1

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

Example 1-1

Now, we can access all the properties and methods of the dictionary.

VBA Dictionary Example 1-2

Note: All the green buttoned words are “Methods,” and others are “Properties.”

Now, declare one variable as “DictResult.”

Dim DictResult As Variant

VBA Dictionary Example 1-3

We will create a new key using the “Dict” variable.

Example 1-4

The Key is what the word we are adding is. So, let’s add the mobile phone name as “Redmi.”

VBA Dictionary Example 1-5

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.

VBA Dictionary Example 1-6

Now, for another variable, “DictResult,” we will add a keyword using the “Dict” variable.

Example 1-7

The Key is the word we have created in the previous step, the name of the phone.

Example 1-8

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

Example 1-9

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

VBA Dictionary Example 1-10

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.

VBA Dictionary Example 2

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.

Леонард Лаудер

Я не строитель зданий, я строитель коллекций

Содержание

  1. Краткое руководство по коллекциям
  2. Введение
  3. Что такое коллекция?
  4. Коллекции против Массивов
  5. Пример: когда Массив лучше
  6. Пример: когда Коллекция лучше
  7. Еще одно преимущество коллекций
  8. Недостаток коллекций
  9. Как создать коллекцию
  10. Незначительная разница между этими методами
  11. Удаление всех элементов из коллекции
  12. Добавление предметов в коллекцию
  13. Before и After
  14. Доступ к элементам коллекции
  15. Элементы в коллекции доступны только для чтения?
  16. Добавление разных типов
  17. Добавление элементов с помощью ключа
  18. Когда использовать ключи
  19. Недостаток использования ключей в коллекциях
  20. Доступ ко всем элементам в коллекции
  21. Использование цикла For
  22. Использование цикла For Each
  23. For Each против For
  24. Скорость
  25. Аккуратнее
  26. Порядок
  27. Сортировка коллекции
  28. Использование коллекций с функциями и подпрограммами
  29. Передача Коллекции в Sub / Function
  30. Передача ByVal против ByRef
  31. Возврат коллекции из функции
  32. Заключение

Краткое руководство по коллекциям

Задача

Пример

Объявить

Dim coll As Collection

Создать во время выполнения

Set coll = New Collection

Объявить и создать

Dim coll As New Collection

Добавить элемент


coll.Add «Яблоко»

Доступ к элементу

coll(1) or coll(2)

Элемент доступа добавлен в
первый раз

coll(1)

Доступ к элементу добавлен в
последний раз

coll(coll.Count)

Получить количество предметов

coll.Count

Доступ ко всем предметам

Dim i As Long
For i = 1 To coll.Count
   
Debug.Print coll(i) 
Next i

Доступ ко всем предметам (For
Each)

Dim fruit As Variant
For Each fruit In coll
   
Debug.Print fruit 
Next fruit

Удалить элемент

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» &amp; 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 делает это самостоятельно. Все, что вам нужно сделать, это добавить элемент или удалить его.

Коллекция используется, когда размер часто изменяется.

Еще одно преимущество коллекций

Коллекции гораздо проще использовать, чем массивы, особенно если вы новичок в программировании. Большую часть времени вы делаете три вещи с коллекциями:

  1. Создать коллекцию
  2. Добавьте несколько предметов
  3. Прочитайте предмет

Так что, если вы не имеете дело с большим количеством предметов, тогда использование Коллекции может быть намного удобнее в использовании.

Недостаток коллекций

Основные типы данных (т.е. переменные, такие как 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. Слива

1

2

3

4

collFruit.Add «Яблоко»

collFruit.Add «Слива»

‘ Добавьте лимон после первого пункта

collFruit.Add «Лимон», After:=1

После этого кода порядок коллекции выглядит так:

  1. Яблоко
  2. Лимон
  3. Слива

Доступ к элементам коллекции

Для доступа к элементам коллекции вы просто используете индекс. Как мы увидели, индекс — это позиция элемента в коллекции на основе порядка, в котором они были добавлены.

Порядок также можно установить с помощью параметра «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

Использование ключей имеет три преимущества:

  1. Если заказ изменится, ваш код все равно получит доступ к нужному товару
  2. Вы можете напрямую получить доступ к элементу, не читая всю коллекцию
  3. Это может сделать ваш код более читабельны

В коллекции 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. Вы не можете обновить значение, хранящееся в ключе

Первый вопрос легко обойти. Следующий код проверяет, существует ли ключ.

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 . Поэтому они очень просты в освоении.

 Основные пункты этой статьи:

  1. Коллекции — это способ хранения группы элементов вместе.
  2. VBA имеет свои собственные коллекции, такие как
    Workbooks, Worksheets и Cells .
  3. Элементы не обязательно должны быть одного типа, но обычно одного. Коллекция VBA Sheets может содержать как листы, так и листы диаграмм.
  4. Коллекция позволяет легко выполнять одну и ту же задачу для нескольких элементов, например, распечатать все значения.
  5. Коллекции похожи на массивы, поскольку в них хранятся группы похожих элементов.
  6. Коллекции лучше при добавлении и удалении большого количества элементов.
  7. Коллекции проще в использовании, чем массивы.
  8. Массивы более полезны, когда количество элементов фиксировано.
  9. Массивы более эффективны при чтении и записи в ячейки или из них .
  10. Базовые типы данных (т.е. не-объекты) в коллекции доступны только для чтения, а массивы — для чтения / записи.
  11. Вы можете создать коллекцию, используя только Dim или Dim с помощью Set.
  12. Вы можете удалить всю коллекцию, установив для нее значение Nothing. Но зависит от того, как она была создана.
  13. Вы можете добавлять элементы в определенную позицию в коллекции, используя аргументы «Before» и «After» с помощью функции Add.
  14. Вы можете использовать ключи с коллекцией для прямого доступа к элементу. Коллекции не имеют хорошей поддержки ключей, поэтому обычно лучше использовать коллекцию Dictionary, когда вам нужно использовать ключи.
  15. Вы можете использовать циклы For и For Each для доступа ко всем элементам в коллекции. Цикл For Each более эффективен, но позволяет просматривать коллекцию только в одном порядке.
  16. Вы можете легко передать коллекцию в качестве аргумента в функцию или подпрограмму.
  17. Вы можете легко вернуть коллекцию из функции.

Источник

Понравилась статья? Поделить с друзьями:
  • Excel vba collapse all
  • Excel vba cell numberformat
  • Excel vba code list
  • Excel vba code execution has been interrupted
  • Excel vba cell in sheet