TỪ ĐIỂN VBA TRONG EXCEL – HƯỚNG DẪN ĐẦY ĐỦ

“Kiệt tác vĩ đại nhất trong văn học chỉ là một cuốn từ điển không theo trật tự.”  – Jean Cocteau.  Trong bài viết này, Học Excel Online sẽ hướng dẫn bạn từ điển VBA  trong Excel  ngay sau đây.

Hướng dẫn nhanh về từ điển VBA

Chức năng Params
Tham chiếu ràng buộc “Microsoft Scripting Runtime” (Thêm bằng Tools -> References từ menu VB)
Khai báo (early blinding) Dim dict As Scripting.Dictionary
Tạo (Early blinding) Set dict = New Scripting.Dictionary
Khai báo (Late binding) Dim dict As Object
Tạo (Late binding) Set dict = CreateObject(“Scripting.Dictionary”)
Thêm Item (Key không được tồn tại) dict.Add Key, Value

e.g. dict.Add “Apples”, 50

Thay đổi giá trị tại Key. Tự động thêm nếu Key không tồn tại. dict(Key) = Value

e.g. dict(“Oranges”) = 60

Nhận giá trị từ từ điển bằng cách sử dụng Key. Value = dict(Key)

e.g. appleCount = dict(“Apples”)

Kiểm tra xem Key có tồn tại không. dict.Exists(Key)

e.g. If dict.Exists(“Apples”) Then

Xóa Item dict.Remove Key

e.g. dict.Remove “Apples”

Xóa tất cả các Item dict.RemoveAll
Xem qua tất cả các Item (cho mỗi vòng lặp) Dim key As Variant

For Each key In dict.Keys

    Debug.Print key, dict(key)

Next key

Xem qua tất cả các Item (cho vòng lặp – chỉ early binding) Dim i As Long

For i = 0 To dict.Count – 1

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

Next i

Xem qua tất cả các Item (cho vòng lặp – 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

Nhận số lượng Item dict.Count
Đặt Key phân biệt chữ hoa chữ thường (từ điển phải trống). dict.CompareMode = vbBinaryCompare
Đặt Key không phân biệt chữ hoa chữ thường (từ điển phải trống). dict.CompareMode = vbTextCompare

 

Từ điển VBA là gì?

Trong VBA, chúng ta sử dụng Mảng và Collection để lưu trữ các nhóm giá trị. Ví dụ, chúng ta có thể sử dụng chúng để lưu trữ danh sách tên khách hàng, điểm của sinh viên hoặc danh sách các giá trị từ một dải ô.

Từ điển tương tự như một Bộ sưu tập. Sử dụng cả hai loại, chúng ta có thể đặt tên cho một Item khi chúng ta thêm nó. Hãy tưởng tượng chúng ta đang lưu trữ số lượng các loại trái cây khác nhau.

Chúng ta có thể sử dụng cả Collection và Dictionary như thế này:

' Add to Dictionary
dict.Add Key:="Apple", Item:=5

' Add to Collection
coll.Add Item:=5, Key:="Apple"
1-TỪ ĐIỂN VBA TRONG EXCEL
1-TỪ ĐIỂN VBA TRONG EXCEL
 

Trong cả hai trường hợp, chúng ta đang lưu trữ giá trị 5 và đặt tên cho nó là “Apple”. Bây giờ chúng ta có thể nhận được giá trị của Apple từ cả hai loại như thế này:

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

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

Càng xa càng tốt. Tuy nhiên, Collection có hai nhược  điểm chính:

  1. Chúng ta không thể kiểm tra xem Key đã tồn tại hay chưa.  
  2. Chúng ta không thể thay đổi giá trị của một mặt hàng hiện có.

Vấn đề đầu tiên khá dễ gặp phải:  Check Collection Key exists. Thứ hai thì khó hơn.

Từ điển VBA không có những vấn đề này. Bạn có thể kiểm tra xem Key có tồn tại hay không và bạn có thể thay đổi Item và Key.

Ví dụ: chúng ta có thể sử dụng mã sau để kiểm tra xem chúng ta có một mặt hàng tên là Apple hay không.

If dict.Exists("Apple") Then 
    dict("Apple") = 78

Những khác biệt này có vẻ rất đơn giản. Tuy nhiên, nó có nghĩa là Từ điển rất hữu ích cho một số nhiệm vụ nhất định. Đặc biệt là khi chúng ta cần lấy giá trị của một Item.

Từ điển trong thực tế

Nếu bạn vẫn chưa hiểu rõ về Từ điển thì hãy nghĩ theo cách này. Một từ điển trên thực tế có một danh sách các Key và các Item. Các Key là các từ và các Item là định nghĩa.

Khi bạn muốn tìm định nghĩa của một từ, bạn chuyển thẳng đến từ đó. Bạn không đọc hết mọi Item trong Từ điển.

Một ví dụ thứ hai trong thực tế là một danh bạ điện thoại (bạn có nhớ không?). Key trong danh bạ điện thoại là tên \ địa chỉ và Item là số điện thoại.  Một lần nữa, bạn sử dụng tổ hợp tên \ địa chỉ để nhanh chóng tìm thấy một số điện thoại.

Trong Excel, hàm VLookup hoạt động theo cách tương tự như một Từ điển. Bạn tìm kiếm một mặt hàng dựa trên một giá trị duy nhất.

Một ví dụ đơn giản về cách sử dụng từ điển VBA

Đoạn mã dưới đây đưa ra một ví dụ đơn giản về việc sử dụng Từ điển. Nó làm như sau:

  1. Thêm ba loại trái cây và một giá trị cho mỗi loại vào Từ điển.  
  2. Người dùng được yêu cầu nhập tên của một loại trái cây.  
  3. Mã kiểm tra xem quả này có trong Từ điển hay không.  
  4. Nếu có thì nó sẽ hiển thị tên trái cây và giá trị.  
  5. Nếu không thì nó sẽ thông báo cho người dùng rằng trái cây không tồn tại.
' 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

Đây là một ví dụ đơn giản nhưng nó cho thấy từ điển hữu ích như thế nào. Chúng ta sẽ xem một ví dụ thực ở phần sau của bài viết. Hãy xem xét những điều cơ bản của việc sử dụng Từ điển.

Tạo từ điển

Để sử dụng Từ điển, trước tiên bạn cần thêm thư viện.

  1. Chọn Tools -> References từ Visual Basic menu.  
  2. Tìm Microsoft Scripting Runtime trong danh sách và đánh dấu vào hộp bên cạnh nó.

Chúng ta khai báo một từ điển như sau:

Dim dict As New Scripting.Dictionary

Hay 

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

Tạo từ điển theo cách này được gọi là “Early Binding”. Ngoài ra còn có “Late Binding”. Hãy xem điều này có nghĩa là gì.

Early vs Late Binding

Để tạo từ điển bằng cách sử dụng Late Binding, chúng ta sử dụng đoạn mã sau.  Chúng tôi không cần thêm một tham chiếu.

Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")

Về mặt kỹ thuật Early binding có nghĩa là chúng ta quyết định chính xác những gì chúng ta đang sử dụng từ trước. Với Late binding, quyết định này được thực hiện khi ứng dụng đang chạy. Nói một cách dễ hiểu, sự khác biệt là:

  1. Early binding cần có thư viện mà chúng ta chọn ở Tools References  . Late binding thì không. 
  2. Early binding cho phép truy cập vào *Intellisense- chức năng gợi khi code/lập trình. Late binding thì không.  
  3. Early binding có thể yêu cầu bạn thêm thủ công Tham chiếu vào “Microsoft Scripting Runtime” cho một số người dùng.

(*Intellisense là tính năng hiển thị cho bạn các thủ tục và thuộc tính có sẵn của một Item khi bạn đang nhập.)

Mặc dù Microsoft khuyên bạn nên sử dụng early binding trong hầu hết các trường hợp, nhưng tôi sẽ khác. Một nguyên tắc chung là early binding khi phát triển mã để bạn có quyền truy cập vào Intellisense. Sử dụng late binding khi phân phối mã cho người dùng khác để ngăn các lỗi xung đột thư viện khác nhau xảy ra.

Thêm các Item vào từ điển

Chức năng Params Ví dụ
Add Key, Item dict.Add “Apples”, 50

Chúng ta có thể thêm các Item vào từ điển bằng chức năng Add. Các Item cũng có thể được thêm bằng cách gán một giá trị mà chúng ta sẽ xem xét trong phần tiếp theo.

Chúng ta hãy xem xét chức năng Add trước. Hàm Add có hai tham số: Key và Item. Cả hai đều là tham số bắt buộc.

Trong ví dụ thêm đầu tiên ở trên, chúng ta sử dụng tên tham số. Bạn không cần phải làm điều này mặc dù nó có thể hữu ích khi bạn bắt đầu.

dict.Add Key:="Orange", Item:=45
dict.Add "Apple", 66
dict.Add "12/12/2015", "John"
dict.Add 1, 45.56

Key có thể là bất kỳ kiểu dữ liệu nào. Item có thể là bất kỳ kiểu dữ liệu nào, một đối tượng (Object), mảng (Array), bộ sưu tập (Collection) hoặc thậm chí là một từ điển (Dictionary). Vì vậy, bạn có thể có một Từ điển của Từ điển, Mảng và Bộ sưu tập. Nhưng hầu hết thời gian nó sẽ là một giá trị (ngày, số hoặc văn bản).

Nếu chúng ta thêm một Key đã tồn tại trong Từ điển thì chúng ta sẽ gặp lỗi

2-TỪ ĐIỂN VBA TRONG EXCEL
2-TỪ ĐIỂN VBA TRONG EXCEL

Đoạn mã sau sẽ đưa ra lỗi này

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

' This line gives an error as key exists already
dict.Add Key:="Orange", Item:=75

Chỉ định một giá trị

Hoạt động Định dạng Ví dụ
Gán giá trị cho một key trong Dictionary (Từ điển) Dictionary(Key) = Item dict(“Oranges”) = 60

Chúng ta có thể thay đổi giá trị của khóa bằng đoạn mã sau

dict("Orange") = 75

Gán giá trị cho Key theo cách này có một tính năng bổ sung. Nếu Key không tồn tại, nó sẽ tự động thêm Key và Item từ điển. Điều này sẽ hữu ích khi bạn có một danh sách các mục đã được sắp xếp và chỉ muốn mục nhập cuối cùng cho mỗi mục.

' Adds Orange to the dictionary 
dict("Orange") = 45 

' Changes the value of Orange to 100
dict("Orange") = 100

Đừng quên rằng bạn có thể tải xuống tất cả mã VBA được sử dụng trong bài đăng này từ đầu hoặc cuối bài đăng.

Kiểm tra Key tồn tại

Chức năng Paraments Ví dụ
Exists Key If dict.Exists(“Apples”) Then

Chúng ta có thể sử dụng hàm Exists để kiểm tra xem Key có tồn tại trong từ điển hay không.

' 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

Lưu trữ nhiều giá trị trong Key

Hãy xem dữ liệu mẫu bên dưới. Chúng ta muốn lưu trữ Amount  và Item cho mỗi Customer ID.

Từ điển chỉ lưu trữ một giá trị vậy chúng ta có thể làm gì?

Chúng ta có thể sử dụng một mảng hoặc tập hợp làm giá trị nhưng điều này là không cần thiết. Cách tốt nhất để làm điều đó là sử dụng Class Module.

Đoạn mã sau đây cho thấy cách chúng ta có thể làm điều này.

' 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

Bạn có thể thấy rằng bằng cách sử dụng Mô-đun Lớp, chúng ta có thể lưu trữ bao nhiêu trường tùy thích. Ví dụ 2 và 3 ở cuối bài đăng cho thấy cách sử dụng mô-đun lớp với Từ điển.

Các chức năng hữu ích khác

Chức năng  Paraments Ví dụ
Count N/A dict.Count
Remove Key dict.Remove “Apples”
Remove all N/A dict.RemoveAll

Ba hàm trong bảng trên thực hiện như sau:

  1. Count – trả về số lượng mục trong Từ điển.  
  2. Remove – loại bỏ một Key nhất định khỏi Từ điển.  
  3. RemoveAll – xóa tất cả các mục khỏi Từ điển

Phần phụ sau đây cho thấy một ví dụ về cách bạn sẽ sử dụng các hàm này.

' 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

Hãy nhớ rằng bạn có thể tải xuống tất cả các ví dụ mã từ bài đăng. Chỉ cần chuyển đến phần tải xuống ở trên cùng.

Key và chữ hoa chữ thường

Một số hàm chuỗi trong VBA có vbCompareMethod. Điều này được sử dụng cho các hàm so sánh các chuỗi. Nó được sử dụng để xác định xem trường hợp của các chữ cái có quan trọng hay không.

Từ điển sử dụng một phương pháp tương tự. Thuộc tính CompareMode của từ điển được sử dụng để xác định xem trường hợp của các key có quan trọng hay không.  Các cài đặt là:

vbTextCompare: Chữ hoa và chữ thường được coi là giống nhau.  

vbBinaryCompare: Chữ hoa và chữ thường được coi là khác nhau. Đây là mặc định.

Với Từ điển, chúng ta có thể sử dụng các cài đặt này để xác định xem trường hợp của các key có quan trọng hay không.

' 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

Lần này chúng ta sử dụng vbTextCompare có nghĩa là trường hợp không thành vấn đề:

' 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

Lưu ý: Từ điển phải trống khi bạn sử dụng thuộc tính CompareMode, nếu không bạn sẽ gặp lỗi: “Invalid procedure call or argument”.

Những điều cần chú ý

vbBinaryCompare (trường hợp quan trọng) là mặc định và điều này có thể dẫn đến các lỗi nhỏ. Ví dụ: hãy tưởng tượng bạn có dữ liệu sau trong các ô A1 đến B2.

Orange, 5

orange, 12

Đoạn mã sau sẽ tạo hai khóa – bật cho “Orange” và một cho “orange”. Điều này tinh tế vì sự khác biệt duy nhất là trường hợp của chữ cái đầu tiên.

' 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

Nếu bạn sử dụng vbTextCompare cho cùng một dữ liệu, bạn sẽ gặp lỗi khi cố gắng thêm key thứ hai vì nó coi “Orange” và “orange” giống nhau.

' 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

Nếu bạn sử dụng phương pháp gán thì nó không tính đến CompareMode . Vì vậy, đoạn mã sau vẫn sẽ thêm hai key mặc dù CompareMode được đặt thành 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

Đọc qua từ điển

Chúng ta có thể đọc qua tất cả các mục trong Từ điển. Chúng ta có thể xem qua các key bằng cách sử dụng vòng lặp For Each. Sau đó, chúng ta sử dụng key hiện tại để truy cập một mục.

Dim k As Variant
For Each k In dict.Keys
    ' Print key and value
    Debug.Print k, dict(k)
Next

Chúng ta cũng có thể lặp lại các key mặc dù tính năng này chỉ hoạt động với Early Binding (Bản cập nhật tháng 2 năm 2020: Trong Office 365, tính năng này hiện hoạt động với cả hai phiên bản):

Dim i As Long
For i = 0 To dict.Count - 1
    Debug.Print dict.Keys(i), dict.Items(i)
Next i

Phương pháp này hoạt động với cả ràng buộc Early và Late binding:

Dim i As Long
For i = 0 To dict.Count - 1
   Debug.Print dict.Keys()(i), dict.Items()(i)
Next i

Sắp xếp từ điển

Đôi khi bạn có thể muốn sắp xếp Từ điển theo kew hoặc theo giá trị.

Từ điển không có chức năng sắp xếp nên bạn phải tự tạo. Tôi đã viết hai hàm sắp xếp – một để sắp xếp theo key và một để sắp xếp theo giá trị.

Sắp xếp theo key

Để sắp xếp từ điển theo key, bạn có thể sử dụng chức năng SortDictionaryByKey bên dưới:

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

Đoạn mã dưới đây cho bạn thấy cách sử dụng 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

Sắp xếp bằng giá trị

Để sắp xếp từ điển theo các giá trị, bạn có thể sử dụng hàm SortDictionaryByValue bên dưới.

‘ 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

Đoạn mã dưới đây hướng dẫn bạn cách sử dụng SortDictionaryByValue

Giải quyết rắc rối từ điển

Phần này bao gồm các lỗi phổ biến mà bạn có thể gặp phải khi sử dụng Từ điển.

Quên tham chiếu

Sự cố: Bạn nhận được thông báo lỗi “User-defined type not defined” 

Điều này thường xảy ra khi bạn tạo Từ điển nhưng quên thêm tham chiếu.

Dim dict As New Scripting.Dictionary

Giải pháp: Chọn Tools->Reference từ menu Visual Basic. Đánh dấu vào hộp bên cạnh “Microsoft Scripting Runtime”.

Xem Phần: Tạo từ điển.

Exists không hoạt động

Sự cố: Bạn đã thêm một key vào Từ điển nhưng khi bạn sử dụng hàm Exists, nó trả về false

Đây thường là một vấn đề với Phân biệt chữ hoa chữ thường (xem ở trên).  

dict.Add "Apple", 4

If dict.Exists("apple") Then
    MsgBox "Exists"
Else
    MsgBox "Does not Exist"
End If

Đoạn mã sau thêm “Apple” làm key. 

Khi chúng ta kiểm tra “apple”, nó sẽ trả về false. Điều này là do nó tính đến trường hợp của các chữ cái:

Bạn có thể đặt thuộc tính CompareMode thành vbTextCompare và điều này sẽ bỏ qua trường hợp:

Dim dict As New Scripting.Dictionary
dict.CompareMode = vbTextCompare

Giải pháp: Đặt CompareMode thành vbTextCompare để bỏ qua trường hợp hoặc đảm bảo dữ liệu của bạn có đúng trường hợp.

Xem Phần: Key và Phân biệt chữ hoa chữ thường

Lỗi biểu tượng

Sự cố: Bạn nhận được thông báo lỗi “Object variable or With block variable not set” khi bạn cố gắng sử dụng Từ điển.

Điều thường xảy ra khi bạn quên sử dụng New trước khi sử dụng Từ điển. Ví dụ, đoạn mã sau sẽ gây ra lỗi này

Dim dict As Scripting.Dictionary
' This line will give "Object variable..." error
dict.Add "Apple", 4

Giải pháp: Sử dụng New keyword khi tạo Từ điển

Dim dict As New Scripting.Dictionary

Hay 

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

Xem phần: Tạo từ điển

Mẹo hữu ích để gỡ rối từ điển

Nếu bạn đang điều tra một vấn đề với Từ điển, có thể hữu ích khi xem nội dung.

Sử dụng mã sau để In từng Key và Item đến 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

Bạn có thể sử dụng nó như thế này

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

Nếu bạn đang xem qua mã, bạn cũng có thể thêm dict.Count vào Cửa sổ xem để xem có bao nhiêu item hiện có trong Từ điển. Nhấp chuột phải vào bất kỳ đâu trong cửa sổ mã và chọn Add Watch. Nhập dict.Count vào hộp văn bản và nhấp vào Ok.

Bạn cũng có thể sử dụng chính Từ điển từ Watch. Thêm Dict vào cửa sổ Watch. Nếu bạn nhấp vào dấu cộng, bạn sẽ thấy nội dung của Từ điển. Điều này có thể hữu ích nhưng nó chỉ hiển thị key chứ không hiển thị item  

Lưu ý: Bạn chỉ có thể xem Watch khi mã đang chạy.

Hãy nhớ rằng bạn có thể tải xuống tất cả các ví dụ mã từ bài đăng. Chỉ cần chuyển đến phần tải xuống ở trên cùng.

Sao chép từ điển vào một mảng

Như chúng ta biết từ điển được tạo thành từ các cặp Key và Giá trị. Từ điển có thuộc tính Keys là một mảng của tất cả các key và thuộc tính Items là một mảng của tất cả các item (tức là giá trị).

Vì cả hai thuộc tính này đều là mảng, chúng ta có thể ghi chúng trực tiếp vào một trang tính như chúng ta sẽ thấy trong phần tiếp theo.  

Nếu chúng ta muốn sao chép mảng Keys hoặc Items sang một mảng mới thì chúng ta có thể làm điều đó rất dễ dàng như sau:

Dim arr As Variant
arr = dict.Keys

Ví dụ sau đây sao chép các mảng Keys Items sang các mảng mới. Sau đó, nội dung của các mảng mới được in vào 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

Khi mã được chạy, bạn sẽ nhận được kết quả sau:

Lưu ý rằng bạn chỉ có thể sao chép mảng Items khi nó chứa các kiểu dữ liệu cơ bản như chuỗi, dài, ngày, kép, v.v. Nếu các item là đối tượng thì bạn không thể sao chép chúng vào một mảng. Thay vào đó, bạn sẽ cần đọc qua từ điển bằng cách sử dụng một vòng lặp.

Viết từ điển vào trang tính

Chúng ta có thể ghi các key hoặc item Từ điển vào trang tính trong một dòng mã.

Khi bạn viết ra các key hoặc item, chúng sẽ được ghi thành một hàng. Nếu bạn muốn ghi chúng vào một cột, bạn có thể sử dụng hàm WorksheetFunction.Transpose.

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

Đoạn mã dưới đây hiển thị các ví dụ về cách ghi Từ điển vào trang tính:

Ví dụ hữu ích về từ điển

Cách dễ nhất để thấy được lợi ích của Từ điển là xem một số ví dụ thực tế về việc sử dụng nó. Vì vậy, trong phần này chúng ta sẽ xem xét một số ví dụ. Bạn có thể lấy cửa sổ làm việc và mã cho các ví dụ này bằng cách nhập email của bạn vào bên dưới:

Ví dụ 1 – Tổng giá trị đơn

Hãy xem một ví dụ thực tế về việc sử dụng từ điển. Dữ liệu của chúng ta cho ví dụ này là các trận Chung kết World Cup từ năm 2014.

Nhiệm vụ của chúng ta ở đây là lấy số bàn thắng ghi được của mỗi đội. 

Điều đầu tiên chúng ta cần làm là đọc tất cả dữ liệu. Đoạn mã sau đây đọc qua tất cả các trận đấu và in tên của hai đội tham gia.

Điều chúng ta muốn làm bây giờ là lưu trữ từng đội và những bàn thắng mà họ ghi được. Khi chúng ta gặp một đội lần đầu tiên, chúng ta thêm tên làm Key và số bàn thắng làm Item.

Nếu đội đã được thêm vào thì chúng ta sẽ cộng tổng số bàn thắng mà họ ghi được trong trận đấu hiện tại.  

Chúng ta có thể sử dụng dòng sau để thêm mục tiêu cho đội hiện tại:

Dòng này rất mạnh.  

Nếu các đội tồn tại trong Từ điển, các bàn thắng hiện tại được thêm vào tổng số bàn thắng hiện tại của đội đó.  

Nếu đội không tồn tại trong Từ điển thì nó sẽ tự động thêm đội vào Từ điển và đặt giá trị cho các mục tiêu.

Ví dụ, hãy tưởng tượng Từ điển có một mục nhập

Key, Value

Brazil, 5

Sau đó

sẽ cập nhật từ điển để bây giờ nó trông như thế này

Key, Value

Brazil, 8

France, 3

Điều này giúp chúng ta không phải viết mã như thế này:

Chúng ta viết các giá trị từ Từ điển vào trang tính như sau:

‘ Write the data from the dictionary to the worksheet

‘ https://excelmacromastery.com/vba-dictionary

Private Sub WriteDictionary(dict As Scripting.Dictionary _

                    , shReport As Worksheet)

    ClearData shReport

    ‘ 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

Chúng ta rõ ràng muốn điểm số được sắp xếp. Nó là dễ dàng hơn nhiều để đọc theo cách này. Không có cách nào dễ dàng để sắp xếp một Từ điển. Cách thực hiện là sao chép tất cả các mục vào một mảng. Sắp xếp mảng và sao chép các item trở lại Từ điển.

Những gì chúng ta có thể làm là sắp xếp dữ liệu khi nó đã được ghi vào trang tính. Chúng ta có thể sử dụng mã sau để thực hiện việc này:

Sub GetTotals cuối cùng của chúng ta trông như thế này:

Khi bạn chạy mã này, bạn sẽ nhận được kết quả sau

Ví dụ 2 – Xử lý nhiều giá trị

Chúng ta sẽ sử dụng dữ liệu từ phần Nhiều giá trị ở trên.

Hãy tưởng tượng dữ liệu này bắt đầu tại ô A1. Sau đó, chúng ta có thể sử dụng đoạn mã dưới đây để đọc vào từ điển.  

Mã này bao gồm hai mục đăng ký để hiển thị dữ liệu:

  1. WriteToImmediate in nội dung của từ điển vào Immediate Window. 
  2. WriteToWorksheet ghi nội dung của từ điển vào trang tính được gọi là Output.

Để chạy ví dụ này:

  1. Tạo một trang tính có tên là Khách hàng.  
  2. Thêm dữ liệu trên vào trang tính bắt đầu từ ô A1.  
  3. Tạo một trang tính có tên là Output và để trống. 
  4. Đi tới Visual Basic Editor(Alt + F11).  
  5. Chọn Tools->Reference và sau đó chọn “Microsoft Scripting Runtime” từ danh sách.  
  6. Tạo một mô-đun lớp mới và thêm đoạn mã đầu tiên từ bên dưới.  
  7. Tạo một mô-đun tiêu chuẩn mới và thêm đoạn mã thứ hai từ bên dưới.  
  8. Nhấn F5 để chạy và chọn Main từ menu.  
  9. Kiểm tra mmediateWindow (Ctrl + G) và trang tính Đầu ra để xem kết quả.

Ví dụ 3 – Tính tổng nhiều giá trị 

Trong ví dụ này, chúng ta sẽ thực hiện một bản cập nhật nhỏ cho Ví dụ 2. Trong ví dụ đó, chỉ có một mục nhập cho mỗi khách hàng trong dữ liệu. 

Lần này sẽ có nhiều mục nhập cho một số khách hàng và chúng ta muốn tính tổng Amount và tổng Items cho từng khách hàng.  

Xem tập dữ liệu cập nhật bên dưới:

Lưu ý: Nếu bạn chạy mã “Example 2” trên dữ liệu có nhiều bản sao của CustomerID, nó sẽ thông báo lỗi “Key already exists error”.

Khi nào bạn sử dụng từ điển

Vậy khi nào bạn nên sử dụng VBA Dictionary? Khi bạn có một nhiệm vụ trong đó:

  1. Bạn có một danh sách các mục duy nhất, ví dụ: quốc gia, số hóa đơn, tên và địa chỉ khách hàng, id dự án, tên sản phẩm, v.v. 
  2. Bạn cần truy xuất giá trị của một mặt hàng duy nhất.

Tác giả: dtnguyen (Nguyễn Đức Thanh)

· · ·

Khóa học mới xuất bản