[TẶNG] Thuật toán lọc tìm kiếm mới trên ComboBox.

Liên hệ QC

Hoàng Trọng Nghĩa

Chuyên gia GPE
Thành viên BQT
Moderator
Tham gia
17/8/08
Bài viết
8,581
Được thích
16,641
Giới tính
Nam
Mặc dù cách lọc mới này cũng là những vòng lặp để duyệt từng hàng trên mảng như những thuật toán lọc hiện hành, nhưng tôi "phát minh" ra một kiểu lọc mới có thể giảm được thời gian từ bằng việc lọc thông thường cho đến nhanh hơn rất nhiều.

Cụ thể là lọc thông thường các coder thường lấy mảng gốc để lọc cho bất cứ từ khóa (key) nào, còn tôi sẽ lọc được mảng nào lưu tạm lại mảng đó để dùng lọc cho các từ khóa sau. Vì vậy khi bạn gõ ký tự đầu tiên sẽ có thời gian lọc như các kiểu lọc thông thường, nhưng từ ký tự thứ 2 và thứ n sẽ giảm dần theo dữ liệu còn lại trên mảng lưu tạm.

Và cứ mỗi ký tự bị xóa nó sẽ trả lại mảng tương ứng đã lọc trước đó cho nên nó không mất thời gian cho việc lọc lại.

Code này tôi viết để lọc cho ComboBox, nhưng nếu ai muốn tùy biến trên TextBox và gán dữ liệu vào ListBox cũng không vấn đề gì.

Và code này tôi xin tặng các bạn nhân mùa dịch khủng khiếp này. Tôi cũng rất mong được các bạn góp ý cho những trường hợp làm cho nó hoàn thiện hơn, nhanh hơn.

Tôi tạm lấy hơn 11 ngàn phường xã trong nước x 10 lần để có số hàng 111,620 dòng để test.

PHP:
Private Sub cbxPhuongXa_Change()
    If cbxPhuongXa.Text = "" Then
        ReDim Preserve priArrPhuongXa(0 To 0)
        cbxPhuongXa.Column = priArrPhuongXa(0)
        GoTo ExitSub
    End If
 
    On Error GoTo ExitSub
    Dim c As Long, lngLenText As Long, lngUbd As Long
 
    lngLenText = Len(cbxPhuongXa.Text)
    lngUbd = UBound(priArrPhuongXa)
     
    c = lngLenText - 1
 
    If Not IsArray(priArrPhuongXa(c)) Then
        cbxPhuongXa.Clear
        ReDim Preserve priArrPhuongXa(0 To lngLenText)
        GoTo ExitSub
    End If
 
    If lngUbd > lngLenText Then
        If Not IsArray(priArrPhuongXa(lngLenText)) Then
            cbxPhuongXa.Clear
            cbxPhuongXa.ForeColor = &H800000
        Else
            cbxPhuongXa.Column = priArrPhuongXa(lngLenText)
        End If
        ReDim Preserve priArrPhuongXa(0 To lngLenText)
        GoTo ExitSub
    End If
     
    If Right(cbxPhuongXa.Text, 1) = "*" Or Right(cbxPhuongXa.Text, 1) = "?" Then
        ReDim Preserve priArrPhuongXa(0 To lngLenText)
        priArrPhuongXa(lngLenText) = priArrPhuongXa(lngUbd)
        GoTo ExitSub
    End If
     
    Dim arrFilter()
    Dim strType As String, strTemp As String, strColOne As String
    Dim n As Long, r As Long, t As Long, uCol As Long, uRow As Long
     
    c = lngLenText - 1
    lRow = LBound(priArrPhuongXa(c), 2): uRow = UBound(priArrPhuongXa(c), 2)
 
    strTemp = UCase(LoaiDauUni(cbxPhuongXa.Text))
    strType = "*" & strTemp & "*"
    strTypeTwo = strTemp & "*"
     
    For r = lRow To uRow
        strColOne = UCase(LoaiDauUni(priArrPhuongXa(c)(0, r)))
        If strColOne Like strType Then
            ReDim Preserve arrFilter(0 To 0, 0 To n)
            arrFilter(0, n) = priArrPhuongXa(c)(0, r)
            n = n + 1
        End If
    Next
 
    If n Then
        ReDim Preserve priArrPhuongXa(0 To lngLenText)
        priArrPhuongXa(lngLenText) = arrFilter
        cbxPhuongXa.Column = arrFilter
    Else
        cbxPhuongXa.Clear
        cbxPhuongXa.ForeColor = &H800000
        ReDim Preserve priArrPhuongXa(0 To lngLenText)
    End If

ExitSub:
    If cbxPhuongXa.ListCount > 0 Then cbxPhuongXa.DropDown
End Sub

Tôi cũng khuyến mại thêm cho các bạn Hàm LoaiDauUni để loại bỏ dấu tiếng Việt kiểu gõ Unicode (dựng sẵn).

PHP:
Function LoaiDauUni(ByVal strText As String) As String
    If strText = "" Then Exit Function
    Static ObjDict As Object
    Static blnInitial As Boolean
 
    If Not blnInitial Then
        Dim c As Byte
        Dim arrNoMarks, arrUnicode
        arrUnicode = Array(192, 193, 194, 195, 200, 201, 202, 204, 205, 210, 211, 212, _
                            213, 217, 218, 221, 224, 225, 226, 227, 232, 233, 234, 236, 237, _
                            242, 243, 244, 245, 249, 250, 253, 258, 259, 272, 273, 296, 297, _
                            360, 361, 416, 417, 431, 432, 7840, 7841, 7842, 7843, 7844, 7845, _
                            7846, 7847, 7848, 7849, 7850, 7851, 7852, 7853, 7854, 7855, 7856, _
                            7857, 7858, 7859, 7860, 7861, 7862, 7863, 7864, 7865, 7866, 7867, _
                            7868, 7869, 7870, 7871, 7872, 7873, 7874, 7875, 7876, 7877, 7878, _
                            7879, 7880, 7881, 7882, 7883, 7884, 7885, 7886, 7887, 7888, 7889, _
                            7890, 7891, 7892, 7893, 7894, 7895, 7896, 7897, 7898, 7899, 7900, _
                            7901, 7902, 7903, 7904, 7905, 7906, 7907, 7908, 7909, 7910, 7911, _
                            7912, 7913, 7914, 7915, 7916, 7917, 7918, 7919, 7920, 7921, 7922, _
                            7923, 7924, 7925, 7926, 7927, 7928, 7929)
        arrNoMarks = Array("A", "A", "A", "A", "E", "E", "E", "I", "I", "O", "O", "O", "O", _
                            "U", "U", "Y", "a", "a", "a", "a", "e", "e", "e", "i", "i", "o", "o", _
                            "o", "o", "u", "u", "y", "A", "a", "D", "d", "I", "i", "U", "u", "O", _
                            "o", "U", "u", "A", "a", "A", "a", "A", "a", "A", "a", "A", "a", "A", _
                            "a", "A", "a", "A", "a", "A", "a", "A", "a", "A", "a", "A", "a", "E", _
                            "e", "E", "e", "E", "e", "E", "e", "E", "e", "E", "e", "E", "e", "E", _
                            "e", "I", "i", "I", "i", "O", "o", "O", "o", "O", "o", "O", "o", "O", _
                            "o", "O", "o", "O", "o", "O", "o", "O", "o", "O", "o", "O", "o", "O", _
                            "o", "U", "u", "U", "u", "U", "u", "U", "u", "U", "u", "U", "u", "U", _
                            "u", "Y", "y", "Y", "y", "Y", "y", "Y", "y")
        Set ObjDict = CreateObject("Scripting.Dictionary")
        For c = 0 To 133
            ObjDict(arrUnicode(c)) = arrNoMarks(c)
        Next
        blnInitial = True
    End If
 
    Dim i As Long, j As Long, lngAscW As Long
    For i = 1 To Len(strText)
        lngAscW = AscW(Mid(strText, i, 1))
        If lngAscW > 191 Then
            Mid(strText, i, 1) = ObjDict.Item(lngAscW)
        End If
    Next
    LoaiDauUni = strText
End Function

P/S: Nếu muốn lọc mà không cần hàm LoaiDauUni để nhanh hơn, hãy xem bài #58.
 

File đính kèm

  • FilterTest-HTN.xlsm
    1.1 MB · Đọc: 246
Lần chỉnh sửa cuối:
Dĩ nhiên là nó sẽ liệt kê tất cả những chữ liên quan đến xa có dấu và không dấu. Bởi vì nó được Loại dấu nên tất cả đều thành "xa".
Cách search khôn ngoan là chọn các từ khóa không phổ biến (kể cả search google).
Nếu đã nhập "xa" thì kết quả phải đủ là "xa" "xã" "xá" "xạ" "xả" đủ cả chứ anh nhỉ.
 
Upvote 0
Tôi chưa thử vì chưa có nhu cầu lọc nhưng theo hình chụp bài 17 thì dù gõ xã hay xa hay bất kỳ cái gì thì list hiện ra cần phải lọc duy nhất. Google đâu có trùng như vậy.
Chỉ một chữ "xa" thôi, google đã cho ra 726 triệu trang web/page/từ căn cứ vào đâu nói nó không trùng? Từ trang này chia sẻ trang kia, copy trang nọ, nó liệt kê tất tần tật.

1631067390333.png
 
Lần chỉnh sửa cuối:
Upvote 0
Cái vụ tìm "xa" phải ra "xá, xạ..." tuỳ theo thuật tìm kiếm mình muốn như thế nào thì viết thôi, không phải qui định phải tìm kiếm giống Google hay công cụ nào khác. Có người thích gõ "xa" thì chỉ hiện kết quả "*xa*", có người làm biếng gõ tiếng Việt có dấu thì muốn tìm "xa" phải hiện đủ các từ có đủ dấu thanh ("xa họi" thì phải trả về kết quả vừa có dấu vừa không dấu. Sống sao cho vừa lòng nhỉ. :D
Tôi nghĩ cứ theo suy luận thông thường là càng thêm dữ liệu thì càng giới hạn tìm kiếm lại là được rồi.
 
Upvote 0
726 triệu kết quả đi nữa, thì cái list hiện ra (có thể đã sort theo thứ tự nhiều người dùng nhất), chỉ trong khoảng 10 - 20 và chắc chắc không trùng. Xem hình bài 22.
Tôi cũng vừa thử file bài 1. Gõ từ khoá đàng hoàng: Tôi muốn tìm Phú Sơn và tôi gõ "phú", nó ra nào là Phụng, nào là Phương, nào là Phùng, nào là Phượng, ...
Nếu lọc tốt thì chỉ có Phú, Phúc, Phún, Phúng, Phút (nếu có xã tên đó).
Chưa nói lọc có nhanh hay không, hay là rất nhanh, tôi thấy gõ ký tự thứ 2 trở đi, nhất là khi gõ dấu, phải chờ khoảng gần 1 giây mới xuất hiện ký tự vừa gõ.

1631068004288.png
 
Upvote 0
Nếu đã nhập "xa" thì kết quả phải đủ là "xa" "xã" "xá" "xạ" "xả" đủ cả chứ anh nhỉ.
Đúng rồi em, nó liệt kê hết tất cả, nhưng cứ nghĩ đi, tổng số phường và tổng số xã nó ngang nhau, như vậy cho rằng số xã nó là 5 ngàn dòng đi sau đó nhân cho 10 lần vậy là chỉ riêng chữ xã đầu câu thôi thì nó đã ngốn hết 50 ngàn dòng rồi còn gì, như vậy 1 xã nó có ít nhất là 10 dòng chưa kể bên trong nó có chứa các chữ xa có dấu.
Bài đã được tự động gộp:

sao của tôi nó mất đi đâu 1 ít ta :D:D:D

View attachment 265636
Do nó thấy GPE nói về nó quá nó đổi thuật toán xóa ngay những bài trùng hay sao ta? kakaka
 
Upvote 0
Xin các bạn bàn thêm về hướng ứng dụng của việc này vô nhập dữ liệu; (Mà chắc là ứng dụng nhập dữ liệu nhân sụ)
Vấn đề nêu ra là nhập địa danh tỉnh-Huyện-Xã (phường) như thế nào:
Nhập chung vô 1 cột hay nhập 3 cột riêng rẽ?
Nếu nhập chung trong 1 cột thì khó ứng dụng đề cương này, nhỉ?
Còn nếu nhập riêng rẽ 3 cột thì mệt mỏi khi ông nhà nước nhập-tách các xã-huyện hay tỉnh.

Chúc các bạn vui khỏe, trãi 2ua đợt dịch IV này!
 
Upvote 0
Xin các bạn bàn thêm về hướng ứng dụng của việc này vô nhập dữ liệu; (Mà chắc là ứng dụng nhập dữ liệu nhân sụ)
Vấn đề nêu ra là nhập địa danh tỉnh-Huyện-Xã (phường) như thế nào:
Nhập chung vô 1 cột hay nhập 3 cột riêng rẽ?
Nếu nhập chung trong 1 cột thì khó ứng dụng đề cương này, nhỉ?
Còn nếu nhập riêng rẽ 3 cột thì mệt mỏi khi ông nhà nước nhập-tách các xã-huyện hay tỉnh.

Chúc các bạn vui khỏe, trãi 2ua đợt dịch IV này!
Đúng là thuật toán này tuy có nhanh nhưng còn có mặt hạn chế chèn chữ. Tuy nhiên chỉ cần dùng thuộc tính .Column để thay thế cho .List để không phải duyệt thêm 1 vòng lặp nữa là đã thấy nhanh hơn rồi. Nói thêm là cái hay ở đây là "mảng ngược" nó có thể "resize" được số dòng mà từ trước đến nay chúng ta không ai phát hiện ra hoặc chưa áp dụng đến.
 
Upvote 0
Cái vụ tìm "xa" phải ra "xá, xạ..." tuỳ theo thuật tìm kiếm mình muốn như thế nào thì viết thôi, không phải qui định phải tìm kiếm giống Google hay công cụ nào khác. Có người thích gõ "xa" thì chỉ hiện kết quả "*xa*", có người làm biếng gõ tiếng Việt có dấu thì muốn tìm "xa" phải hiện đủ các từ có đủ dấu thanh ("xa họi" thì phải trả về kết quả vừa có dấu vừa không dấu. Sống sao cho vừa lòng nhỉ. :D
Tôi nghĩ cứ theo suy luận thông thường là càng thêm dữ liệu thì càng giới hạn tìm kiếm lại là được rồi.
em lại thít kiểu này
Capture 2.JPGCapture 1.JPGCapture 3.JPG
 
Upvote 0
Xin các bạn bàn thêm về hướng ứng dụng của việc này vô nhập dữ liệu; (Mà chắc là ứng dụng nhập dữ liệu nhân sụ)
Vấn đề nêu ra là nhập địa danh tỉnh-Huyện-Xã (phường) như thế nào:
Nhập chung vô 1 cột hay nhập 3 cột riêng rẽ?
Nếu nhập chung trong 1 cột thì khó ứng dụng đề cương này, nhỉ?
Còn nếu nhập riêng rẽ 3 cột thì mệt mỏi khi ông nhà nước nhập-tách các xã-huyện hay tỉnh.

Chúc các bạn vui khỏe, trãi 2ua đợt dịch IV này!
Hi bác Sa,
Về ứng dụng trong việc nhập liệu nhanh, chính xác thì trước đây em thấy anh @ndu96081631 đã có làm hàm Filter2DArray. em quay lại ứng dụng về nhập liệu, có thể lọc, sắp xếp theo nhiều tiêu chí. Data nguồn thì đang lấy từ một FIle khác, để tránh việc chỉnh sửa dữ liệu gốc.

 
Lần chỉnh sửa cuối:
Upvote 0
Tôi thấy kết hợp lại cũng có mặt tốt:
- nếu gõ "xa" chữ không dấu: Liệt kê các từ chứa nhóm chữ "xa" không dấu và cả có dấu (đủ 5 dấu, trừ dấu tạo ra từ không có nghĩa hoặc không có trong danh sách)
- nếu gõ có dấu, thì ví dụ trong danh sách phường xã có xã "Xạ Hương" hay "Hương Xạ" gì đó, tôi gõ thêm dấu nặng thành "xạ" thì chỉ liệt kê phường xã có chữ "xạ" mà thôi. xã xả xá gì đó phải loại ra. Nếu tôi tìm "xạ" mà liệt kê ra 50 ngàn chữ "xã" thì coi như tìm kiếm cũng như không. Cũng như ví dụ bài trên tôi nói về "phú", nếu tôi gõ "phú" thì chỉ còn "phú", "Phúc", "Phút" chứ không có phương, phường, phượng gì hết
- Nếu tôi gõ chữ không dấu kèm 1 khoảng trắng ("xa "), nghĩa là tôi dứt khoát chọn không dấu, thì chỉ còn xa, không còn xã xạ xả xá xà gì hết
Và quan trọng là list hiện ra để chọn đã lọc trùng. Về lý thuyết khi đã nói danh sách sẽ rút ngắn khi gõ thêm ký tự thì phải rút ngắn.
 
Upvote 0
Tôi thấy kết hợp lại cũng có mặt tốt:
- nếu gõ "xa" chữ không dấu: Liệt kê các từ chứa nhóm chữ "xa" không dấu và cả có dấu (đủ 5 dấu, trừ dấu tạo ra từ không có nghĩa hoặc không có trong danh sách)
- nếu gõ có dấu, thì ví dụ trong danh sách phường xã có xã "Xạ Hương" hay "Hương Xạ" gì đó, tôi gõ thêm dấu nặng thành "xạ" thì chỉ liệt kê phường xã có chữ "xạ" mà thôi. xã xả xá gì đó phải loại ra. Nếu tôi tìm "xạ" mà liệt kê ra 50 ngàn chữ "xã" thì coi như tìm kiếm cũng như không. Cũng như ví dụ bài trên tôi nói về "phú", nếu tôi gõ "phú" thì chỉ còn "phú", "Phúc", "Phút" chứ không có phương, phường, phượng gì hết
- Nếu tôi gõ chữ không dấu kèm 1 khoảng trắng ("xa "), nghĩa là tôi dứt khoát chọn không dấu, thì chỉ còn xa, không còn xã xạ xả xá xà gì hết
Và quan trọng là list hiện ra để chọn đã lọc trùng. Về lý thuyết khi đã nói danh sách sẽ rút ngắn khi gõ thêm ký tự thì phải rút ngắn.
Cái điều đơn giản hết sức đó tưởng người mới viết code thắc mắc còn coi được. Chỉ cần xóa cái hàm LoaiDauUni ra thì được rồi, vả lại nó còn nhanh hơn rất nhiều.
 
Upvote 0
Cái điều đơn giản hết sức đó tưởng người mới viết code thắc mắc còn coi được. Chỉ cần xóa cái hàm LoaiDauUni ra thì được rồi, vả lại nó còn nhanh hơn rất nhiều.
1. Tiêu đề của chủ đề là "TẶNG" viết hoa, và trong bài viết là xin nhận "góp ý cho những trường hợp làm cho nó hoàn thiện hơn". Tôi thấy những góp ý từ anh @batman1 , đến @Cá ngừ F1, @HieuCD đến tôi, chưa thấy nhận là đúng hay là sai, cũng không nhận để sửa cho hoàn thiện, cả việc gõ 2, 3 ký tự xong phải 1 giây sau mới hiện ra, cũng không thấy "làm cho hoàn thiện hơn".
Cho nên tôi thấy cần phải ghi ra những nhận xét để mọi thành viên biết khi nhận quà TẶNG sẽ được hưởng những gì. Huống hồ tôi đang trả lời ý chung cho cụ thể là bài của @thuyyeu99
2. Nếu xoá hàm đó ra mà xài thì không chắc người nhận quà TẶNG đã biết cách xoá. Nhận xong không xài đúng ý mình thì chắc không nhận.
 
Upvote 0
Hi bác Sa,
Về ứng dụng trong việc nhập liệu nhanh, chính xác thì trước đây em thấy anh @NDU đã có làm hàm Filter2DArray. em quay lại ứng dụng về nhập liệu, có thể lọc, sắp xếp theo nhiều tiêu chí. Data nguồn thì đang lấy từ một FIle khác, để tránh việc chỉnh sửa dữ liệu gốc.

Mình tin cái hàm Filter2DArray này khi sử dụng trên ComboBox hay ListBox thì có thể cải tiến để chạy nhanh hơn và không cần dùng tới Dic để ghim số hàng.
 
Upvote 0
1. Tiêu đề của chủ đề là "TẶNG" viết hoa, và trong bài viết là xin nhận "góp ý cho những trường hợp làm cho nó hoàn thiện hơn". Tôi thấy những góp ý từ anh @batman1 , đến @Cá ngừ F1, @HieuCD đến tôi, chưa thấy nhận là đúng hay là sai, cũng không nhận để sửa cho hoàn thiện, cả việc gõ 2, 3 ký tự xong phải 1 giây sau mới hiện ra, cũng không thấy "làm cho hoàn thiện hơn".
Cho nên tôi thấy cần phải ghi ra những nhận xét để mọi thành viên biết khi nhận quà TẶNG sẽ được hưởng những gì. Huống hồ tôi đang trả lời ý chung cho cụ thể là bài của @thuyyeu99
2. Nếu xoá hàm đó ra mà xài thì không chắc người nhận quà TẶNG đã biết cách xoá. Nhận xong không xài đúng ý mình thì chắc không nhận.
Vâng hihi.
Cái mục đích em nói là khi viết nhằm để người dùng có thể thao tác tìm kiếm thuận tiện nhất và kết quả sát với từ mình tìm kiếm nhất để dễ nhìn nhất.
Cái hình em Post Chữ đồng là 1800 kết quả, chữ đông là 3230 kết quả. Còn cái kia là nó sẽ láy hết dong, đông, đòng.....
Còn về thuật toán em không nhận xét
Bài đã được tự động gộp:

Form này có nhiều tuỳ chọn. Mục tiêu cuối cùng là thiết kế để người dùng có thể thao tác tìm kiếm thuận tiện nhất, ít bối rối nhất là tốt rồi.
Combobox theo em thì có nhiều cái bất tiện và nhìn không đẹp nên em không mặn mà lắm nên em lấy cái form đó làm Combobox luôn
 
Lần chỉnh sửa cuối:
Upvote 0
Combobox theo em thì có nhiều cái bất tiện và nhìn không đẹp nên em không mặn mà lắm nên em lấy cái form đó làm Combobox luôn

Đúng hay đó em. Thiết kế thì không nên bó buộc trong những cái mặc định của ứng dụng. Chẳng hạn như cái MsgBox, đâu nhất thiết phải dùng cái Msgbox của hệ thống, có thể dùng Form làm Msgbox để tuỳ biến được cao hơn, phù hợp với ứng dụng mình đang viết. :)
 
Upvote 0
Tôi chưa thử vì chưa có nhu cầu lọc nhưng theo hình chụp bài 17 thì dù gõ xã hay xa hay bất kỳ cái gì thì list hiện ra cần phải lọc duy nhất. Google đâu có trùng như vậy.
Đây chỉ là ví dụ nhanh và bàn về lọc thôi. Không có chỗ nào nói về lọc duy nhất mà anh.
Muốn lọc duy nhất thì chỉ cần làm 1 lần: lọc duy nhất rồi mới đưa vào mảng gốc.
Bài đã được tự động gộp:

Nếu đã nhập "xa" thì kết quả phải đủ là "xa" "xã" "xá" "xạ" "xả" đủ cả chứ anh nhỉ.
Code tôi viết là tìm đúng. Gõ Xa thì chỉ tìm Xa. Xem các bài của tôi thì thấy tôi chỉ trích kiểu gõ Phu mà lại tìm cả Phù, Phủ, Phũ, Phú, Phụ (bài #8). Không tìm kiểu "gần đúng" là dụng ý của tôi mà. Chả nhẽ tôi chỉ trích kiểu tìm như thế mà tôi lại viết code để tìm kiểu như thế?
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT
Back
Top Bottom