Dictionary & Collection ?

Liên hệ QC

Hoàng Nhật Phương

Thành viên gắn bó
Tham gia
5/11/15
Bài viết
1,894
Được thích
1,214
Xin chào các Bạn,
Đầu xuân chúc mọi người luôn mạnh khỏe & bình an.
----
Như tiêu đề OT đã nêu, OT có đọc bài viết của Bạn Collection @befaint nhưng có lẽ do kiến thức còn hạn hẹp nên chưa thể hiểu hết về sự khác biệt giữa Dictionary & Collection,
Ví dụ trong 2 đoạn code dưới đây sử dụng Dictionary & Collection cho cùng một công việc:
Mã:
Option Explicit

Sub CollectionFilter()
Dim TT As Double
TT = Timer
Dim myCol As Collection
Set myCol = New Collection
Dim i As Long, lRow As Long, ArrData(), Result(), sKey As String, j As Long
With Sheet1
    lRow = .Range("B" & Rows.Count).End(xlUp).Row
    ArrData = .Range("B2:D" & lRow).Value2
    lRow = UBound(ArrData, 1)
    ReDim Result(1 To lRow, 1 To 4)
    For i = 1 To lRow
        sKey = ArrData(i, 1)
        If sKey <> "" Then
            If KeyExists(myCol, sKey) = False Then
                j = j + 1
                myCol.Add j, sKey
                Result(j, 1) = j
                Result(j, 2) = sKey
                Result(j, 3) = ArrData(i, 2)
                Result(j, 4) = ArrData(i, 3)
            Else
                Result(myCol.Item(sKey), 4) = Result(myCol.Item(sKey), 4) + ArrData(i, 3)
             End If
        End If
    Next i
    If j > 0 Then
        .Range("M2").Resize(100, 4).ClearContents
        .Range("M2").Resize(j, 4) = Result
        .Range("Q7") = Timer - TT
    End If
End With


End Sub


Sub DictionaryFilter()
Dim TT As Double
TT = Timer

Dim Dic As Object
Dim i As Long, lRow As Long, ArrData(), Result(), sKey As String, j As Long
Set Dic = CreateObject("Scripting.Dictionary")
With Sheet1
    lRow = .Range("B" & Rows.Count).End(xlUp).Row
    ArrData = .Range("B2:D" & lRow).Value2
    lRow = UBound(ArrData, 1)
    ReDim Result(1 To lRow, 1 To 4)
    For i = 1 To lRow
        sKey = ArrData(i, 1)
        If sKey <> "" Then
            If Not Dic.Exists(sKey) Then
                j = j + 1
                Dic.Add sKey, j
                Result(j, 1) = j
                Result(j, 2) = sKey
                Result(j, 3) = ArrData(i, 2)
                Result(j, 4) = ArrData(i, 3)
            Else
                Result(Dic.Item(sKey), 4) = Result(Dic.Item(sKey), 4) + ArrData(i, 3)
            End If
        End If
    Next i
    If j > 0 Then
        .Range("H2").Resize(100, 4).ClearContents
        .Range("H2").Resize(j, 4) = Result
        .Range("L7") = Timer - TT
    End If
End With

End Sub
Trên máy tính của OT có vẻ như Collection nhanh hơn Dictionary :
1613618736712.png

Nhờ các bạn chỉ dẫn cho OT hiểu rõ thêm trong trường hợp nào thì dùng cái nào sẽ tối ưu hơn?
Tại sao Collection nhanh hơn Dictionary mà không thấy mọi người sử dụng Collection mà thường sử dụng Dictionary hơn hay do thói quen ạ?
 

File đính kèm

  • Collection.xlsb
    1.2 MB · Đọc: 13
Lần chỉnh sửa cuối:
Chốt lại là theo kinh nghiệm của chú Mỹ & anh Nghĩa thì OT thấy dù dữ liệu ít hay nhiều thì cứ nên sử dụng Dictionary cho ổn định vì dữ liệu ít thì khỏi bàn về tốc độ còn dữ liệu nhiều thì cứ Dictionary mà dùng ạ?
----
Vấn đề là trong phạm vi bài toán yêu cầu chỉ sử dụng Collection & Dictionary không dược phép sử dụng cái khác (như For...next...)
- Trường hợp nào bắt buộc phải dùng Dictionary mà không thể dùng Collection.
- Trường hợp nào bắt buộc phải dùng Collection mà không thể dùng Dictionary.
=> Thì chưa có ví dụ cụ thể ạ... nên OT cũng không thấy được về mục đích sử dụng cũng giống như bài toán phân biệt giữa ByVal & ByRef vậy.
Thằng nào mà chả dùng vòng lặp For em? Chẳng qua "cơ cấu" thằng nào nhanh hơn thôi.
 
Upvote 0
Thay vì hỏi, thay vì làm theo kinh nghiệm của người khác thì mình tự thử nghiệm 4 cái gạch đầu dòng ở bài #5 ấy, để tự mình có kinh nghiệm của chính mình. Lúc đó hoàn toàn tự tin nêu ra kinh nghiệm của chính mình.
Và đảm bảo rằng, sau khi thử nghiệm xong 4 cái mục đó sẽ biết cái nào nên dùng vào trường hợp nào? Cũng tới lúc tìm hiểu cái mới, không nên cứ bám theo cái đã cũ.
 
Upvote 0
Cái này là anh sử dụng 'Form' khi chạy code OT không thấy hiện hiện cái Form là sao anh Nghĩa nhỉ? Hay là xử lý 'ngầm gì đó qua Form' thì tốc độ nhanh hơn vậy anh?
Form vẫn hoạt động, nhưng nó không được Show ra thôi em. Nó nhanh hơn For ... Next mà không dùng công cụ nào, bởi nó có thuộc tính Match Found nên rất nhanh.
 
Upvote 0
Thay vì hỏi, thay vì làm theo kinh nghiệm của người khác thì mình tự thử nghiệm 4 cái gạch đầu dòng ở bài #5 ấy, để tự mình có kinh nghiệm của chính mình. Lúc đó hoàn toàn tự tin nêu ra kinh nghiệm của chính mình.
Và đảm bảo rằng, sau khi thử nghiệm xong 4 cái mục đó sẽ biết cái nào nên dùng vào trường hợp nào? Cũng tới lúc tìm hiểu cái mới, không nên cứ bám theo cái đã cũ.
Cảm ơn Bạn nhiều @befaint
Phiền Bạn có thể chỉ dẫn cụ thể cho OT biết cách làm thử nghiệm và kiểm tra vấn đề này được không @befaint , có video ví dụ kèm theo thì là tốt nhất ạ.
- Add nhiều lần 1 key <--- thử nghiệm phần kiểm tra sự tồn tại key trong object;
- Add nhiều keys không trùng lần nào <--- kiểm tra Add key vào object;
 
Upvote 0
- Add nhiều keys không trùng lần nào <--- kiểm tra Add key vào object;
Trong file ở bài đó làm rồi còn gì.

- Add nhiều lần 1 key <--- thử nghiệm phần kiểm tra sự tồn tại key trong object;

Const key = "key_xyz" '---> Đây là 1 key
Const num = 2000000
Dim i as long
For i = 1 to num
'kiem tra key khong co trong object '(*)
'add key vào object
object.add key, "" '---> add nhiều lần 1 key, thực ra là add có 1 lần, chỉ thử nghiệm cái dòng trên (*) thôi.
Next i.

Mình cứ đọc ---- thật ---- chậm thôi.
 
Upvote 0
Xin chào anh Nghĩa đẹp trai,
nghĩa là nếu chỉ cần xác định Key trùng hay không cứ 'ForNext' trong 'mảng':
Mã:
Private Function KeyExists(Result, sKey, j, k) As Boolean
    For k = 1 To j
        If Result(k, 2) = sKey Then
            KeyExists = True
            Exit For
        End If
    Next k
End Function
thì lúc nào cũng nhanh hơn là Collection,Dictionary phải không phải ạ?
huuthang_bd đã nói rõ là code viết cho bài #1, tức trường hợp cụ thể. Tập tin của bạn có 100009 dòng dữ liệu nhưng chỉ có (tôi không kiểm tra mà chỉ nhìn kết quả mà bạn nhập tay) 6 Mã khác nhau (Mã nhiều vô kể nhưng trùng cực nhiều, tức số Mã duy nhất là rất ít). Bạn hãy thử sửa dữ liệu sao cho có khoảng 50 000 Mã duy nhất, hoặc tất cả 100 009 Mã đều khác nhau từng đôi một rôi kiểm tra lại xem có đúng là luôn có For ... Next nhanh hơn hay không.

Muốn so sánh collection và dictionary thì dễ thôi.
1. So sánh về chức năng.
Bạn có biết collection và dictionary có những thuộc tính và phương thức nào không? Dĩ nhiên bạn đọc nhiều bài lý thuyết và bạn đã biết. Vậy thì cứ so sánh từng phương thức và từng thuộc tính thôi. Cả 2 có phương thức ADD không? Nếu có thì có cùng dễ dùng không? Có thuộc tính nào mà collection có nhưng dictionary không có, hoặc ngược lại không. Cái đó có là ưu điểm lớn không? Vd. dictionary có thuộc tính KEYS, ITEMS. Collection có không? Nếu không có thì KEYS, ITEMS có là điểm mạnh đáng mơ ước hay không.
Cứ so sánh từng phương thức, thuộc tính như thế.

2. So sánh về tốc độ?
Nghĩ ra vài bài toán, vài thể loại. Với mỗi bài thì chọn dữ liệu đa dạng. Tức lúc thì dữ liệu ít, lúc thì dữ liệu nhiều, cực nhiều. Lúc thì dữ kiệu cực nhiều nhưng số key duy nhất ít, lúc thì số key duy nhất nhiều nhiều, lúc thì tất cả các key là duy nhất.
 
Upvote 0
Chốt lại là theo kinh nghiệm của chú Mỹ ...
Tôi viết nhầm bài trên: sửa và bổ sung như sau:
- Khi dữ liệu 1 triệu dòng, keys 10.000 cái, thì Dict và Collection tương đương, nhanh chậm hơn vài phần trăm giây
- Khi dữ liệu 10 ngàn dòng,, keys 9 ngàn, Dict rất rất chậm thậm chí chậm hơn thí dụ trên, Collection nhanh hơn 1 tẹo. Nên dùng thứ khác như là HashTable
- Với dữ liệu vừa phải (50 ngàn dòng, khá ít keys), Collection nhanh hơn gấp đôi (chỉ cho việc add key, không tính phần code xử lý dữ liệu)
PHP:
Sub ExtractByCollection()

t = Timer
   Dim sArrID()
    Dim ColDM As Collection
    Dim EndR As Long
With Sheet20
    EndR = .Cells(65536, 1).End(xlUp).Row
    sArrID = .Range("G4:G" & EndR).Value2
End With
    Set ColDM = New Collection
For i = 1 To UBound(sArrID, 1)
    If Not KeyExists(ColDM, sArrID(i, 1)) Then
        k = k + 1
        ColDM.Add Item:=k, Key:=sArrID(i, 1)
    End If
Next
MsgBox Timer - t '0.125'
End Sub
/////
Function KeyExists(myCol As Collection, ByVal keyCheck As String) As Boolean
    KeyExists = False
    On Error GoTo EndFunction
    myCol.Item keyCheck
    KeyExists = True
EndFunction:
End Function
////
Sub ExtractByDictionary()
t = Timer
   Dim sArrID()
    Dim DictDM
    Dim EndR As Long
With Sheet20
    EndR = .Cells(65536, 1).End(xlUp).Row
    sArrID = .Range("G4:G" & EndR).Value2
End With
    Set DictDM = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(sArrID, 1)
    If Not DictDM.Exists(sArrID(i, 1)) Then
        k = k + 1
        DictDM.Add sArrID(i, 1), k
    End If
Next
MsgBox Timer - t '0.325'
End Sub
File đính kèm chứa 50 ngàn dòng dữ liệu, 12 keys, Dict = 0.325 giây, Collect = 0.125 giây
Chạy ra báo cáo cũng nhanh hơn (sheet THNXT)
Khuyến mãi ảnh cháu ngoại mùng 4 tết

1613648313348.png
 

File đính kèm

  • CollectAndDict.xlsm
    3.3 MB · Đọc: 19
Lần chỉnh sửa cuối:
Upvote 0
...
- Khi dữ liệu 1 triệu dòng, keys 10.000 cái, thì Dict và Collection tương đương, nhanh chậm hơn vài phần trăm giây
- Khi dữ liệu 10 ngàn dòng,, keys 9 ngàn, Dict rất rất chậm thậm chí chậm hơn thí dụ trên, Collection nhanh hơn 1 tẹo.
Cho nên đừng tuyên bố cái nào nhanh hơn cái nào.
Liệt kê của bạn còn thiếu tính chất của keys nữa.

Tại mọi người đọc bài #11, chỉ nghe đến "nhanh/chậm" là tối mắt hết rồi.
Nếu chịu khó mở mắt ra nhìn cho kỹ ngay đầu, người viết có nói:
"Với dữ liệu ở bài #1..."

Dữ liệu ấy có hơn 100 ngàn dòng, nhưng chỉ có 6 trị keys, mỗi trị key chỉ là chuỗi 5 ký tự.
Hàm tìm chỉ phải chạy 6 dòng trong mảng dò. Trung bình là 3 lượt. Và so sánh 5 ký tự cũng dễ bẹt.
Với đít sần, mỗi lần thử thì hàm băm phải băm 5 ký tự ấy ra, dùng trị băm đưa vào bảng dò. Nếu tôi không lầm thì đít sần trong thư viện script dùng cấu trúc b-tree để làm mục lục bảng băm. Chỉ có 6 nodes thì chưa chắc b-tree đã hiệu quả hơn mảng.
Túm lại, phân tích ra như sau:
1. với chỉ 5 ký tự thì so sánh thẳng nhanh hơn thảy vào cối mà băm.
2. với chỉ 6 phần tử thì mảng đi cái ọt, xong trước khi b-tree nó đọc được cái gốc (root) của nó, chưa chắc đã đến cái lá nào.

Chú: vì số keys rất ít, và keys rất ngắn cho nên tôi làm cái pivot table cũng chạy cái ọt. Thử 100 ngàn dòng 50 ngàn keys, 50 ký tự xem pivot có nổi không?

Pót xong mới thấy bác kia viết bài #27, phân tích đại khái cũng như tôi.
 
Upvote 0
huuthang_bd đã nói rõ là code viết cho bài #1, tức trường hợp cụ thể. Tập tin của bạn có 100009 dòng dữ liệu nhưng chỉ có (tôi không kiểm tra mà chỉ nhìn kết quả mà bạn nhập tay) 6 Mã khác nhau (Mã nhiều vô kể nhưng trùng cực nhiều, tức số Mã duy nhất là rất ít). Bạn hãy thử sửa dữ liệu sao cho có khoảng 50 000 Mã duy nhất, hoặc tất cả 100 009 Mã đều khác nhau từng đôi một rôi kiểm tra lại xem có đúng là luôn có For ... Next nhanh hơn hay không.

Muốn so sánh collection và dictionary thì dễ thôi.
1. So sánh về chức năng.
Bạn có biết collection và dictionary có những thuộc tính và phương thức nào không? Dĩ nhiên bạn đọc nhiều bài lý thuyết và bạn đã biết. Vậy thì cứ so sánh từng phương thức và từng thuộc tính thôi. Cả 2 có phương thức ADD không? Nếu có thì có cùng dễ dùng không? Có thuộc tính nào mà collection có nhưng dictionary không có, hoặc ngược lại không. Cái đó có là ưu điểm lớn không? Vd. dictionary có thuộc tính KEYS, ITEMS. Collection có không? Nếu không có thì KEYS, ITEMS có là điểm mạnh đáng mơ ước hay không.
Cứ so sánh từng phương thức, thuộc tính như thế.

2. So sánh về tốc độ?
Nghĩ ra vài bài toán, vài thể loại. Với mỗi bài thì chọn dữ liệu đa dạng. Tức lúc thì dữ liệu ít, lúc thì dữ liệu nhiều, cực nhiều. Lúc thì dữ kiệu cực nhiều nhưng số key duy nhất ít, lúc thì số key duy nhất nhiều nhiều, lúc thì tất cả các key là duy nhất.
Con chào Bác, cảm ơn Bác đã chỉ dẫn ạ.
Dạ đúng mới đầu suy nghĩ của con chỉ muốn tìm hiểu rõ về chức năng ạ, trong trường hợp nào dùng được Dic mà không thể dùng được collection ấy ạ và ngược lại bởi vì qua bài viết con đưa ở bài 1 con thấy collection có phần nhanh hơn nên con muốn hỏi thêm...
Sau nhiều bài viết thì con cũng đã hiểu sơ sơ chỉ là một chút thôi ạ vì chưa ngồi test cụ thể được.
Có lẽ tạm thời con xin phép chỉ theo dõi để các Bác và những người có kiến thức chuyên sâu thảo luận thêm ạ,vì bắt đầu trở lại với công việc hàng ngày và tối về bọn trẻ ăn với lại học online nên con cũng bận không như mấy hôm nghỉ tết ạ.
Sau khi nghiên cứu mổ sẻ có chỗ nào không hiểu con lại hỏi ở đây ạ.
 
Upvote 0
...
File đính kèm chứa 50 ngàn dòng dữ liệu, 12 keys, Dict = 0.325 giây, Collect = 0.125 giây
Code của bạn dùng đít sần ở dạng kết nối trễ.
Đã thử kết nối sớm chưa?

Tôi nhớ mang máng đọc ở đâu trong mớ tài liệu của MS về Office Automation thì kết nối trễ sẽ gọi hàm theo kiểu gián tiếp, và sẽ chậm gấp bội lần trực tiếp.
 
Upvote 0
Code của bạn dùng đít sần ở dạng kết nối trễ.
Đã thử kết nối sớm chưa?

Tôi nhớ mang máng đọc ở đâu trong mớ tài liệu của MS về Office Automation thì kết nối trễ sẽ gọi hàm theo kiểu gián tiếp, và sẽ chậm gấp bội lần trực tiếp.
Khai báo sớm, thời gian còn khoảng 1/5 so với khai báo trễ, với file ở bài 28, code Add đơn thuần, và nhanh hơn Collect :p :p :p. Cả code báo cáo cũng trở nên nhanh hơn Collection.
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi viết nhầm bài trên: sửa và bổ sung như sau:
- Khi dữ liệu 1 triệu dòng, keys 10.000 cái, thì Dict và Collection tương đương, nhanh chậm hơn vài phần trăm giây
- Khi dữ liệu 10 ngàn dòng,, keys 9 ngàn, Dict rất rất chậm thậm chí chậm hơn thí dụ trên, Collection nhanh hơn 1 tẹo. Nên dùng thứ khác như là HashTable
- Với dữ liệu vừa phải (50 ngàn dòng, khá ít keys), Collection nhanh hơn gấp đôi (chỉ cho việc add key, không tính phần code xử lý dữ liệu)
PHP:
Sub ExtractByCollection()

t = Timer
   Dim sArrID()
    Dim ColDM As Collection
    Dim EndR As Long
With Sheet20
    EndR = .Cells(65536, 1).End(xlUp).Row
    sArrID = .Range("G4:G" & EndR).Value2
End With
    Set ColDM = New Collection
For i = 1 To UBound(sArrID, 1)
    If Not KeyExists(ColDM, sArrID(i, 1)) Then
        k = k + 1
        ColDM.Add Item:=k, Key:=sArrID(i, 1)
    End If
Next
MsgBox Timer - t '0.125'
End Sub
/////
Function KeyExists(myCol As Collection, ByVal keyCheck As String) As Boolean
    KeyExists = False
    On Error GoTo EndFunction
    myCol.Item keyCheck
    KeyExists = True
EndFunction:
End Function
////
Sub ExtractByDictionary()
t = Timer
   Dim sArrID()
    Dim DictDM
    Dim EndR As Long
With Sheet20
    EndR = .Cells(65536, 1).End(xlUp).Row
    sArrID = .Range("G4:G" & EndR).Value2
End With
    Set DictDM = CreateObject("Scripting.Dictionary")
For i = 1 To UBound(sArrID, 1)
    If Not DictDM.Exists(sArrID(i, 1)) Then
        k = k + 1
        DictDM.Add sArrID(i, 1), k
    End If
Next
MsgBox Timer - t '0.325'
End Sub
File đính kèm chứa 50 ngàn dòng dữ liệu, 12 keys, Dict = 0.325 giây, Collect = 0.125 giây
Chạy ra báo cáo cũng nhanh hơn (sheet THNXT)
Khuyến mãi ảnh cháu ngoại mùng 4 tết

View attachment 254272

Các bé lúc nào cũng dễ thương & đáng yêu tự nhiên, có lẽ do sự trong sáng tạo nên Chú Mỹ nhỉ.
Con test thử đoạn sau cũng thấy tốc độ chênh lệch giữa Collection & Dic gần gấp đôi:
Mã:
Option Explicit

Dim T As Double, sKey As String , i As Long, k As Long
Const r As Long = 666666

Function KeyExists(myCol As Collection, ByVal keyCheck As String) As Boolean
    KeyExists = False
    On Error GoTo EndFunction
    myCol.Item keyCheck
    KeyExists = True
EndFunction:
End Function

Sub Test_Collection()
    T = Timer
    Dim Coll As Collection
    Set Coll = New Collection
    k = 0
    For i = r To 1 Step -2
        sKey = i / 2 '& i
        If Not KeyExists(Coll, sKey) Then
            k = k + 1
            Coll.Add Item:=k, Key:=sKey
        End If
    Next i
    Debug.Print "sKey: " & k & "---" & "Collection time: " & Timer - T
    'sKey: 333333---Collection time: 2.7265625
End Sub

Sub Test_Dictionary()
    T = Timer
    Dim Dic
    Set Dic = CreateObject("Scripting.Dictionary")
    k = 0
    For i = r To 1 Step -2
        sKey = i / 2 '& i
        If Not Dic.Exists(sKey) Then
            k = k + 1
            Dic.Add sKey, k
        End If
    Next i
    Debug.Print "sKey: " & k & "---" & "Dictionary time: " & Timer - T
    'sKey: 333333---Dictionary time: 4.8203125
End Sub
Và con đang tìm xem test với trường hợp nào Dic lợi thế hơn...
 
Upvote 0
Dic tuy nhanh hơn trước nhưng vẫn thua xa col Chú ạ:
View attachment 254276
Tin hay không tùy bạn, nhưng mình dám khẳng định rằng cách bạn đang học code sai trầm trọng. Đó là nguyên nhân tại sao bạn học code bấy lâu nay mà chưa đâu vào đâu. Nếu là tôi thì tôi không dại gì đua tốc độ, càng không nên so sánh khập khiễng giữa Collection và Dictionary. So sánh kiểu đi tìm câu trả lời cho câu hỏi "Tiền và Tình, cái nào quan trọng hơn?" Có thể bây giờ bạn chưa tin, thời gian sau này có thể bạn sẽ phải tin. Vài lời chân tình, bạn hãy suy gẫm nhé.
 
Upvote 0
Tin hay không tùy bạn, nhưng mình dám khẳng định rằng cách bạn đang học code sai trầm trọng. Đó là nguyên nhân tại sao bạn học code bấy lâu nay mà chưa đâu vào đâu. Nếu là tôi thì tôi không dại gì đua tốc độ, càng không nên so sánh khập khiễng giữa Collection và Dictionary. So sánh kiểu đi tìm câu trả lời cho câu hỏi "Tiền và Tình, cái nào quan trọng hơn?" Có thể bây giờ bạn chưa tin, thời gian sau này có thể bạn sẽ phải tin. Vài lời chân tình, bạn hãy suy gẫm nhé.
Dạ Anh, OT vẫn đang loay hoay tìm hiểu từng vấn đề mà anh, giờ mà dính tìm hiểu về 'tình' nữa thì chìm không còn sức lực để sống nữa Anh }}}}}
Vừa rồi là tốc độ,còn giờ là đang so sánh tính năng ạ.
OT đang thấy phần bôi vàng Dic chiếm ưu thế hơn Col ạ:

1613668655190.png
 

File đính kèm

  • Dictionary & Collection.xlsx
    13.5 KB · Đọc: 6
Upvote 0
huuthang_bd đã nói rõ là code viết cho bài #1, tức trường hợp cụ thể. Tập tin của bạn có 100009 dòng dữ liệu nhưng chỉ có (tôi không kiểm tra mà chỉ nhìn kết quả mà bạn nhập tay) 6 Mã khác nhau (Mã nhiều vô kể nhưng trùng cực nhiều, tức số Mã duy nhất là rất ít). Bạn hãy thử sửa dữ liệu sao cho có khoảng 50 000 Mã duy nhất, hoặc tất cả 100 009 Mã đều khác nhau từng đôi một rôi kiểm tra lại xem có đúng là luôn có For ... Next nhanh hơn hay không.

Muốn so sánh collection và dictionary thì dễ thôi.
1. So sánh về chức năng.
Bạn có biết collection và dictionary có những thuộc tính và phương thức nào không? Dĩ nhiên bạn đọc nhiều bài lý thuyết và bạn đã biết. Vậy thì cứ so sánh từng phương thức và từng thuộc tính thôi. Cả 2 có phương thức ADD không? Nếu có thì có cùng dễ dùng không? Có thuộc tính nào mà collection có nhưng dictionary không có, hoặc ngược lại không. Cái đó có là ưu điểm lớn không? Vd. dictionary có thuộc tính KEYS, ITEMS. Collection có không? Nếu không có thì KEYS, ITEMS có là điểm mạnh đáng mơ ước hay không.
Cứ so sánh từng phương thức, thuộc tính như thế.

2. So sánh về tốc độ?
Nghĩ ra vài bài toán, vài thể loại. Với mỗi bài thì chọn dữ liệu đa dạng. Tức lúc thì dữ liệu ít, lúc thì dữ liệu nhiều, cực nhiều. Lúc thì dữ kiệu cực nhiều nhưng số key duy nhất ít, lúc thì số key duy nhất nhiều nhiều, lúc thì tất cả các key là duy nhất.
Con chào Bác,
Sau một hồi test , có lẽ con đã hiểu thêm một chút xíu nữa Bác ạ, cụ thể con cảm nhận như sau:
- Về chức năng Dic hơn hẳn Col (con nêu ở bài 38).
- Về tốc độ (con mô tổ toàn bộ đoạn code phía dưới):
Key càng nhiều thì Col càng nhanh Dic càng chậm mà ForNext thì thôi siêu chậm ạ.
Key ít thì Col sẽ chậm hơn Dic một chút và ForNext sẽ nhanh ạ.

Mã:
Option Explicit

Private Const r As Long = 666666
Dim T As Double, sKey As String, i As Long, j As Long, k As Long

Private Function KeyExists_ForNext(Result, sKey, j, k) As Boolean
For k = 1 To j
    If Result(k, 1) = sKey Then
        KeyExists_ForNext = True
        Exit For
    End If
Next k
End Function

Sub ForNext()
    T = Timer
    Const n As Long = 666666
    'Const n As Long =65000
    Dim Result(1 To n, 1 To 1)
    k = 0: j = 0
    For i = n To 1 Step -1
        'sKey = i / 2
        sKey = i Mod 3
        If Not KeyExists_ForNext(Result, sKey, j, k) Then
            j = j + 1
            Result(j, 1) = sKey
        End If
    Next i
    Debug.Print "sKey: " & j & " --- " & "ForNext time: " & Timer - T
    'Neu: sKey = i / 2 va n  = 65000
    'sKey: 32500 --- ForNext time: 42.98193359375
    
    'Neu: sKey = i Mod 3 va n  = 666666 (=r)
    'sKey: 3 --- ForNext time: 0.09814453125
End Sub


Private Function KeyExists(myCol As Collection, ByVal keyCheck As String) As Boolean
    KeyExists = False
    On Error GoTo EndFunction
    myCol.Item keyCheck
    KeyExists = True
EndFunction:
End Function

Sub Test_Collection()
    T = Timer
    Dim Coll As Collection
    Set Coll = New Collection
    k = 0
    For i = r To 1 Step -1
        sKey = i / 2
        'sKey = i Mod 3
        If Not KeyExists(Coll, sKey) Then
            k = k + 1
            Coll.Add Item:=k, Key:=sKey
        End If
    Next i
    Debug.Print "sKey: " & k & " --- " & "Collection time: " & Timer - T
    'Neu: sKey = i / 2
    'sKey: 666666 --- Collection time: 5.291015625
    
    'Neu: sKey = i Mod 3
    'sKey: 3 --- Collection time: 0.23583984375
End Sub

Sub Test_Dictionary()
    T = Timer
    Dim Dic As New Scripting.Dictionary
    k = 0
    For i = r To 1 Step -1
        'sKey = i / 2
        sKey = i Mod 3
        If Not Dic.Exists(sKey) Then
            k = k + 1
            Dic.Add sKey, k
        End If
    Next i
    Debug.Print "sKey: " & k & " --- " & "Dictionary time: " & Timer - T
    'Neu: sKey = i / 2
    'sKey: 666666 --- Dictionary time: 18.06591796875
    
    'Neu: sKey = i Mod 3
    'sKey: 3 --- Dictionary time: 0.06396484375
End Sub

Con mới hiểu chừng đó, có gì Bác chỉ dẫn thêm ạ.
Xin cảm ơn tất cả mọi người đã chỉ dẫn cho OT ạ, hic OT ngủ để mai còn đi làm đi làm ạ @@!
 
Upvote 0
Key càng nhiều thì Col càng nhanh Dic càng chậm mà ForNext thì thôi siêu chậm ạ.
Cũng tùy theo bạn cho là thế nào là nhiều. Về lý thuyết thì có thể có vd. 1 hoặc 2 triệu Mã khác nhau, nhưng trong bài toán thực tế mà hàng ngày bạn phải giải quyết thì số các Mã khác nhau nó thuộc cỡ nào? Bạn không phải là những ông giáo sư ngồi trên bàn nhậu bàn về lý thuyết. Bạn là nhà thực hành, giải quyết các bài toán trong thực tế. Bài toán với 1 triệu Mã khác nhau thường gặp hơn hay bài toán với 1000 hoặc 100 000 Mã khác nhau hay gặp hơn trong cuộc sống? 100 000 Mã KHÁC NHAU là con số NHIỀU chưa? Nếu đó là con số lớn, thực tế hơn, thì trong 2 code test bạn sửa thành sKey = i Mod 100000 rồi test xem có còn Key càng nhiều thì Col càng nhanh Dic càng chậm không nhé.

Theo tôi bạn nên tạm gác chuyện tốc độ sang một bên. Nếu tôi hiểu thì bạn chưa hiểu hết collection, dictionary. Vậy thì trước hết hãy hiểu chúng, sử dụng chúng thuần thục. Còn khi gặp bài toán cụ thể mà bạn thấy dictionary chậm thì lúc đó tìm cách khác cũng chả bao giờ muộn.

1. Collection:
- key không thể là số (không quan trọng lắm), không thể là OBJECT (nhược điểm lớn)
- Chỉ có Remove, không thể xóa hết các item, key (chỉ còn nước hủy đối tượng và tạo lại)
- không có phương thức Exists, Items, Keys
- không có thuộc tính Key
- không dùng được trong các tập tin VBS (dùng VB Script)
- với key không phân biệt hoa thường. Tức nếu đã có key là "Hic hic" thì không thể thêm key mới là "hic hic".

2. Dictionary:
- key có thể là chuỗi, số và OBJECT (vd. là đít sần khác)
- có Remove và RemoveAll
- có phương thức Exists, Items, Keys
- có thuộc tính Key cho phép thay đổi giá trị key đang tồn tại.
- dùng được trong các tập tin VBS (dùng VB Script)
- có thuộc tính CompareMode nên có thể chủ động phân biệt hoa thường hay không.

Chính vì những hạn chế của collection nên theo tôi nếu có thể code đơn giản cho bài toán nào đấy bằg collection thì cũng code được đơn giản bằng đít sần, nhưng ngược lại không đúng. Có những bài mà có thể code đơn giản dùng đít sần nhưng không làm đơn giản được bằng collection.
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom