Thắc mắc,góp ý hoàn thiện về hàm UDF Filter2DArray (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

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,662
Được thích
16,725
Giới tính
Nam
PHP:
Function Filter2DArray(ByVal sArray, ByVal ColIndex As Long, ByVal FindStr As String, ByVal HasTitle As Boolean)
  Dim tmpArr, i As Long, j As Long, Arr, Dic, TmpStr, Tmp, Chk As Boolean, TmpVal As Double
  On Error Resume Next
  Set Dic = CreateObject("Scripting.Dictionary")
  tmpArr = sArray
  ColIndex = ColIndex + LBound(tmpArr, 2) - 1
  Chk = (InStr("><=", Left(FindStr, 1)) > 0)
  For i = LBound(tmpArr, 1) - HasTitle To UBound(tmpArr, 1)
    If Chk Then
      TmpVal = CDbl(tmpArr(i, ColIndex))
      If Evaluate(TmpVal & FindStr) Then Dic.Add i, ""
    Else
      If UCase(tmpArr(i, ColIndex)) Like UCase(FindStr) Then Dic.Add i, ""
    End If
  Next
  If Dic.Count > 0 Then
    Tmp = Dic.Keys
    ReDim Arr(LBound(tmpArr, 1) To UBound(Tmp) + LBound(tmpArr, 1) - HasTitle, LBound(tmpArr, 2) To UBound(tmpArr, 2))
    For i = LBound(tmpArr, 1) - HasTitle To UBound(Tmp) + LBound(tmpArr, 1) - HasTitle
      For j = LBound(tmpArr, 2) To UBound(tmpArr, 2)
        Arr(i, j) = tmpArr(Tmp(i - LBound(tmpArr, 1) + HasTitle), j)
      Next
    Next
    If HasTitle Then
      For j = LBound(tmpArr, 2) To UBound(tmpArr, 2)
        Arr(LBound(tmpArr, 1), j) = tmpArr(LBound(tmpArr, 1), j)
      Next
    End If
  End If
  Filter2DArray = Arr
End Function

Hàm Filter mãng 2 chiều này thật là hay, tôi đã ứng dụng rất nhiều bài tập, song hình như nó có vẽ như thiếu thứ gì đó, với trình độ của tôi thì đọc Hàm trên chỉ biết là vậy chứ thật sự không hiểu hết nổi thuật toán mà Thầy ndu96081631 đã thực hiện. Vì vậy tôi muốn hỏi là:

1) Làm thế nào để Lọc điều kiện là rỗng?

2) Giữ tất cả, Trừ điều kiện là rỗng?

Xin cảm ơn rất nhiều!
 

File đính kèm

PHP:
1) Làm thế nào để Lọc điều kiện là rỗng?
2) Giữ tất cả, Trừ điều kiện là rỗng?
Xin cảm ơn rất nhiều![/QUOTE]
Đầu tiên sửa code lại 1 chút
Đoạn[B] If Chk Then[/B] sửa thành [B]If Chk And FindStr <> "" Then[/B]
1> Lấy giá trị rổng, điều kiện là: cứ để trống bình thường
2> Lấy giá trị <> rổng, điều kiện là:: [B][\W
----------------------
[/B]Bạn bôi đen chữ[B] Like [/B]trong code, bấm [B]F1[/B] xem help để biết thêm chi tiết
[I](Nói thật, code này cũng khá hoàn chỉnh rồi nhưng tôi vẫn chưa hài lòng lắm ---> Các bạn có điều kiện nghiên cứu hãy cải tiến giúp tôi với)[/I]
 
Lần chỉnh sửa cuối:
Upvote 0
Đầu tiên sửa code lại 1 chút
Đoạn If Chk Then sửa thành If Chk And FindStr <> "" Then
1> Lấy giá trị rổng, điều kiện là: cứ để trống bình thường
2> Lấy giá trị <> rổng, điều kiện là:: [\W
----------------------
Bạn bôi đen chữ Like trong code, bấm F1 xem help để biết thêm chi tiết
(Nói thật, code này cũng khá hoàn chỉnh rồi nhưng tôi vẫn chưa hài lòng lắm ---> Các bạn có điều kiện nghiên cứu hãy cải tiến giúp tôi với)

Cám ơn Thầy đã chỉ dạy! Riêng điều kiện [\W thì em thử dùng điều kiện chỉ là [ nó vẫn cho ra giá trị đúng. Vậy có gì khác nhau không thưa Thầy?
 
Upvote 0
Cám ơn Thầy đã chỉ dạy! Riêng điều kiện [\W thì em thử dùng điều kiện chỉ là [ nó vẫn cho ra giá trị đúng. Vậy có gì khác nhau không thưa Thầy?
Toán tử Like này rất hay nhưng cũng khá.. BAO LA... Tôi vẫn đang cố nắm bắt, có những cái vẫn chưa hiểu bạn à
(Tới đâu nghiên cứu tới đấy thôi)
 
Upvote 0
Không hiểu sao, đối với File này, TRUE OR FALSE vẫn bị dính cái tiêu đề cột??? Không biết mình ghi sai cấu trúc gì?


Mã:
Private Sub FillterRoroc()
  
  Roroc.[A19:F100].ClearContents
  
  Dim sArray1, Arr1
  
  sArray1 = CSDL.Range(CSDL.[A1], CSDL.[A65536].End(xlUp)).Resize(, 12)
  
  Arr1 = Filter2DArray(sArray1, 10, "[", [COLOR=#0000cd][B]False[/B][/COLOR])[COLOR=#008000] '<< False hay True van dinh tieu de???[/COLOR]
  
  Roroc.[A19].Resize(UBound(Arr1, 1), 4).Value = Arr1
    
End Sub

Kể cả hàm Unique:

Mã:
Sub UniqueFALSE()

  Sheet2.Range("A2:D8").ClearContents
  
  Dim i As Long, sArray, Arr1, Arr2
  
  sArray = Range(CSDL.[A1], CSDL.[A65536].End(xlUp)).Resize(, 9)
  
  Arr1 = Unique2DArray(sArray, 1, False) '<< False hay True van dinh tieu de???

  If IsArray(Arr1) Then Sheet2.Range("A2").Resize(UBound(Arr1, 1), 4).Value = Arr1
  
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Không hiểu sao, đối với File này, TRUE OR FALSE vẫn bị dính cái tiêu đề cột??? Không biết mình ghi sai cấu trúc gì?


Mã:
Private Sub FillterRoroc()
  
  Roroc.[A19:F100].ClearContents
  
  Dim sArray1, Arr1
  
  sArray1 = CSDL.Range(CSDL.[A1], CSDL.[A65536].End(xlUp)).Resize(, 12)
  
  Arr1 = Filter2DArray(sArray1, 10, "[", [COLOR=#0000cd][B]False[/B][/COLOR])[COLOR=#008000] '<< False hay True van dinh tieu de???[/COLOR]
  
  Roroc.[A19].Resize(UBound(Arr1, 1), 4).Value = Arr1
    
End Sub
Thì sArray1 = CSDL.Range(CSDL.[A1], CSDL.[A65536].End(xlUp)).Resize(, 12)
Bạn lấy dữ liệu từ A1, đương nhiên phải dính luôn tiêu đề rồi ---> Chuyện thường
- Dữ liệu do bạn tự xác đính
- Dữ liệu ấy có bao gồm tiêu đề hay không cũng do bạn xác định
- Xác định sai, ra kết quả sai
Kết luận: Thay A1 thành A2 là hết chuyện
(hãy xem cách vận hành của chức năng Remove Duplicate hoặc Sort thì biết liền)
 
Upvote 0
Thì sArray1 = CSDL.Range(CSDL.[A1], CSDL.[A65536].End(xlUp)).Resize(, 12)
Bạn lấy dữ liệu từ A1, đương nhiên phải dính luôn tiêu đề rồi ---> Chuyện thường
- Dữ liệu do bạn tự xác đính
- Dữ liệu ấy có bao gồm tiêu đề hay không cũng do bạn xác định
- Xác định sai, ra kết quả sai
Kết luận: Thay A1 thành A2 là hết chuyện
(hãy xem cách vận hành của chức năng Remove Duplicate hoặc Sort thì biết liền)

Không được đâu Thầy ơi, Thầy thử xem File sẽ thấy rằng A1 thành A2 là chưa đúng!
 

File đính kèm

Upvote 0
Điên quá đi à!
Filter False và Unique False thì phải từ A2, Filter True và Unique True thì phải từ A1 chứ?
Để hết ở A1 cũng la làng, biểu đổi thì lại đổi hết qua A2 rồi la làng tiếp.
 
Lần chỉnh sửa cuối:
Upvote 0
Điên quá đi à!
Filter False và Unique False thì phải từ A2, Filter True và Unique True thì phải từ A1 chứ?
Để hết ở A1 cũng la làng, biểu đổi thì lại đổi hết qua A2 rồi vẫn la làng.

Trời ơi, Thầy nói vậy thì thêm Boolean làm gì chứ! Phải bao hết rồi có hay không do True hay False quyết định chứ!

Theo em nghĩ thì nếu giữ luôn A1 thì khi TRUE ta để nguyên, không thay đổi; khi FALSE thì giống như OFFSET(1) vậy.
 
Lần chỉnh sửa cuối:
Upvote 0
Trời ơi, Thầy nói vậy thì thêm Boolean làm gì chứ! Phải bao hết rồi có hay không do True hay False quyết định chứ!

Theo em nghĩ thì nếu giữ luôn A1 thì khi TRUE ta để nguyên, không thay đổi; khi FALSE thì giống như OFFSET(1) vậy.
Ừ nhỉ. Nhưng code ndu viết nào cộng nào trừ LBound, UBound, HasTitle tùm lum, chưa thấy lỗi chỗ nào.

Phát biểu sau đây sai:
Đã thấy lỗi Hàm Unique:
1. Thay If HasTitle Then thành If HasTitle = False Then
2. Thay
Mã:
        For j = LBound(TmpArr, 2) To UBound(TmpArr, 2)
          Arr(i - HasTitle + LBound(TmpArr, 1), j) = TmpArr(.Item(KeyArr(i)), j)
        Next

Bằng
Mã:
        For j = LBound(TmpArr, 2) To UBound(TmpArr, 2)
          Arr(i + LBound(TmpArr, 1), j) = TmpArr(.Item(KeyArr(i)), j)
        Next
 
Lần chỉnh sửa cuối:
Upvote 0
Không được đâu Thầy ơi, Thầy thử xem File sẽ thấy rằng A1 thành A2 là chưa đúng!
Tôi đã kiểm tra, hổng thấy cho nào là không đúng cả! Chỉ vì bạn hiểu sai nên kết quả sai
- Muốn lấy tiêu đề, đương nhiên dữ liệu sArray phải bao gồm luôn tiêu đề (tức bắt đầu từ A1)
- Không muốn lấy tiêu để, đương nhiêu dữ liệu sArray phải bỏ qua tiêu đề (tức bắt đầu từ A2)
Vậy:
1> Có lấy tiêu đề:
Mã:
Sub FillterTRUE()
  Roroc.[A19:F100].ClearContents
  Dim sArray1, Arr1
  sArray1 = CSDL.Range(CSDL.[[COLOR=#ff0000][B]A1[/B][/COLOR]], CSDL.[A65536].End(xlUp)).Resize(, 12)
  Arr1 = Filter2DArray(sArray1, 10, "[", [COLOR=#ff0000][B]True[/B][/COLOR]) '<< False hay True van dinh tieu de???
  Roroc.[A19].Resize(UBound(Arr1, 1), 4).Value = Arr1
End Sub
2> Không lấy tiêu đề:
Mã:
Sub UniqueFALSE()
  Sheet2.Range("A2:D8").ClearContents
  Dim sArray, Arr1, Arr2
  sArray = Range(CSDL.[[B][COLOR=#ff0000]A2][/COLOR][/B], CSDL.[A65536].End(xlUp)).Resize(, 9)
  Arr1 = Unique2DArray(sArray, 1, [COLOR=#ff0000][B]False[/B][/COLOR])
  If IsArray(Arr1) Then Sheet2.Range("A2").Resize(UBound(Arr1, 1), 4).Value = Arr1
End Sub
Đơn giản như khi bạn dùng chức năng sort của Excel thôi
------------------------------
Không có lỗi gì đâu sư phụ à! Chẳng qua minhthien chưa hiểu hàm này thôi
-----------------------------
Trời ơi, Thầy nói vậy thì thêm Boolean làm gì chứ! Phải bao hết rồi có hay không do True hay False quyết định chứ!

Theo em nghĩ thì nếu giữ luôn A1 thì khi TRUE ta để nguyên, không thay đổi; khi FALSE thì giống như OFFSET(1) vậy.
Nói vậy là không đúng! Khi dùng sort của Excel, bạn không chỉ rõ thì làm sao nó biết bạn muốn lấy tiêu đề hay không? Và muốn lấy tiêu đề thì đương nhiên bạn phải chọn dữ liệu cho đúng! Bạn chọn sai thì ông Bill cũng chẳng hiểu nổi
(Đã nói bạn nghiên cứu sort mà không chịu nghe)
 
Lần chỉnh sửa cuối:
Upvote 0
Minh thien sai làm lão chết tiệt lính quýnh sai theo à.
Giải thích lại:
Đối với sort:
- Nếu tô chọn cả tiêu đề: phải chọn "có tiêu đề"
- Nếu không tô chọn tiêu đề: phải chọn "không tiêu đề"

Đối với 2 hàm của ta:
- Nếu tô chọn cả tiêu đề: cũng phải chọn "có tiêu đề"
- Nếu không tô chọn tiêu đề: cũng phải chọn "không tiêu đề"

Khi thực hành sai:
- Nếu tô chọn cả tiêu đề mà chọn "Không tiêu đề": Dòng tiêu đề bị xem là dòng dữ liệu, và bị xử lý như là dữ liệu duy nhất hoặc dữ liệu thoả điều kiện lọc, và vẫn hiện ra.
- Nếu không tô chọn cả tiêu đề mà chọn "có tiêu đề": Dòng dữ liệu đầu bị xem là tiêu đề, và nếu dữ liệu đó trùng, sẽ bị hiện ra 1 lần nữa.


Ý của Minh Thien lại khác, hắn muốn:
Dù lúc nào cũng tô chọn tiêu đề, nhưng:
- Nếu chọn "Có tiêu đê", Hàm - Thủ tục sẽ xử lý từ dòng 2 trở xuống
- Nếu chọn "Không tiêu đề", Hàm - thủ tục sẽ xử lý từ dòng 1 trở xuống.

Nghĩa là MinhThien sai, và lão chết tiệt: ban đầu đúng, sau đó lính quýnh sai theo. (Chắc đói)
 
Upvote 0
Ý kiến của em không sai đâu, em lấy một ví dụ cụ thể như sau: (sorry vì lấy hàm Unique để so sánh, hàm này của Sư phụ PTM):

PHP:
Function UniqueList2D(UniqueCol As Long, sArray)
  Dim ReArr()
  Dim iRw, iRws, iCols, iCol, iCount
  iRws = UBound(sArray, 1)
  iCols = UBound(sArray, 2)
  On Error Resume Next
  With CreateObject("Scripting.Dictionary")
        For iRw = 1 To iRws
          If sArray(iRw, UniqueCol) <> "" Then
            If Not .Exists(sArray(iRw, UniqueCol)) Then
                .Add sArray(iRw, UniqueCol), ""
                iCount = iCount + 1
                ReDim Preserve ReArr(1 To iCols, 1 To iCount)
                For iCol = 1 To iCols
                   ReArr(iCol, iCount) = sArray(iRw, iCol)
                Next
            End If
          End If
    Next
    UniqueList2D = Application.Transpose(ReArr)
  End With
End Function

Nếu lọc không trùng và lấy tiêu tiêu đề:

Mã:
Sub UniqueTRUE()

  Sheet2.Range("A2:D8").ClearContents
  
  Dim sArray, Arr
  
  sArray = Range(CSDL.[[COLOR=#ff0000][B]A1[/B][/COLOR]], CSDL.[A65536].End(xlUp)).Resize(, 9).Cells
  
  Arr = UniqueList2D(1, sArray)

  Sheet2.Range("A1").Resize(UBound(Arr, 1), 4).Value = Arr
  
End Sub

Nếu lọc không trùng và không lấy tiêu đề:

Mã:
Sub UniqueFALSE()

  Sheet2.Range("A2:D8").ClearContents
  
  Dim sArray, Arr
  
  sArray = Range(CSDL.[[COLOR=#ff0000][B]A2[/B][/COLOR]], CSDL.[A65536].End(xlUp)).Resize(, 9).Cells
  
  Arr = UniqueList2D(1, sArray)

  Sheet2.Range("A1").Resize(UBound(Arr, 1), 4).Value = Arr
  
End Sub

Ngay từ đầu, do ta chọn vùng dữ liệu và kết quả hoàn toàn chính xác.

Như vậy có cần thêm cái Boolean để tính toán hay không? Trong khi ngay ban đầu cũng đã chọn khối dữ liệu như vậy?
 

File đính kèm

Upvote 0
Minh thien sai làm lão chết tiệt lính quýnh sai theo à.
Giải thích lại:
Đối với sort:
- Nếu tô chọn cả tiêu đề: phải chọn "có tiêu đề"
- Nếu không tô chọn tiêu đề: phải chọn "không tiêu đề"

Đối với 2 hàm của ta:
- Nếu tô chọn cả tiêu đề: cũng phải chọn "có tiêu đề"
- Nếu không tô chọn tiêu đề: cũng phải chọn "không tiêu đề"

Khi thực hành sai:
- Nếu tô chọn cả tiêu đề mà chọn "Không tiêu đề": Dòng tiêu đề bị xem là dòng dữ liệu, và bị xử lý như là dữ liệu duy nhất hoặc dữ liệu thoả điều kiện lọc, và vẫn hiện ra.
- Nếu không tô chọn cả tiêu đề mà chọn "có tiêu đề": Dòng dữ liệu đầu bị xem là tiêu đề, và nếu dữ liệu đó trùng, sẽ bị hiện ra 1 lần nữa.


Ý của Minh Thien lại khác, hắn muốn:
Dù lúc nào cũng tô chọn tiêu đề, nhưng:
- Nếu chọn "Có tiêu đê", Hàm - Thủ tục sẽ xử lý từ dòng 2 trở xuống
- Nếu chọn "Không tiêu đề", Hàm - thủ tục sẽ xử lý từ dòng 1 trở xuống.

Nghĩa là MinhThien sai, và lão chết tiệt: ban đầu đúng, sau đó lính quýnh sai theo. (Chắc đói)
Theo em nghĩ thì trong sort phải như thế này chứ anh:
Đối với sort:
- Nếu đã tô chọn cả tiêu đề:
+ Khi chọn "có tiêu đề" => Hàm - thủ tục sẽ xử lý từ dòng 2 trở xuống.
+ Khi chọn "không tiêu đề" => Hàm - thủ tục sẽ xử lý từ dòng 1 trở xuống.
Không nhất thiết phải là: - Nếu tô chọn cả tiêu đề: phải chọn "có tiêu đề"
(Ý của minhthien không phải không có lý,về hàm của chú ndu thì không có ý kiến)
 
Upvote 0
Ban đầu tôi cũng cho rằng tham số đó là không cần thiết nên không đưa vào. Cơ sở lập luận của code này là: tiêu đề luôn luôn là text nhằm mô tả dữ liệu, theo tiêu chuẩn CSDL. Do đó tiêu đề và dữ liệu không bao giờ giống nhau.
Muốn lấy cả tiêu đề thì lấy range nguồn bao gồm cả dòng tiêu đề. Nghĩa là trong mọi trường hợp, code xử lý tất cả các dòng.

Còn ndu lập luận: Có thể tiêu đề là số từ 1 đến 10 chẳng hạn. Và giả sử lọc duy nhất theo cột 7, là 1 trường số.

1. Nếu không có tham số HasTitle, và có chọn dữ liệu nguồn có bao gồm dòng tiêu đề, thì dòng tiêu đề đương nhiên được lấy.
Sau đó, nếu 1 dòng dữ liệu nào đó, cột 7 có giá trị 7, thì dòng đó không được lấy nữa, vì trùng với dòng đầu tiên.


2. Nếu có tham số HasTitle, người dùng tuỳ biến theo ý muốn:
- Nếu chọn 1 vùng dữ liệu và chọn True, Code xử lý từ dòng thứ 2 trở xuống, sau đó mới add dòng 1 là tiêu đề vào.
- Nếu chọn 1 vùng dữ liệu và chọn False, Code xử lý tất cả các dòng như là dữ liệu

Note:
Cùng 1 lúc, và kể cả sau này, không lẽ chạy 1 lúc vừa True vừa False? Căn cứ vào dữ liệu nguồn và mẫu báo cáo kết quả, người dùng quyết định có nên lấy cả tiêu đề CSDL vào báo cáo hay không. Lúc đó người dùng sẽ chọn chỉ 1 trong 2, và xài luôn năm này qua năm khác chứ?

Đừng làm lão chết tiệt quýnh lên nữa nha.
 
Lần chỉnh sửa cuối:
Upvote 0
Theo em nghĩ thì trong sort phải như thế này chứ anh:
Đối với sort:
- Nếu đã tô chọn cả tiêu đề:
+ Khi chọn "có tiêu đề" => Hàm - thủ tục sẽ xử lý từ dòng 2 trở xuống.
+ Khi chọn "không tiêu đề" => Hàm - thủ tục sẽ xử lý từ dòng 1 trở xuống.
Không nhất thiết phải là: - Nếu tô chọn cả tiêu đề: phải chọn "có tiêu đề"
Nói lại cho rõ hơn:

1. Khi sort, và tô chọn dữ liệu bao gồm dòng tiêu đề, phải đánh dấu vào ô "My data range has header row", nếu không, tiêu đề cũng bị sort và chạy mất tiêu xuống dưới.
Vậy đối với hàm của ndu, khi tô chọn dữ liệu bao gồm dòng tiêu đề, phải chọn True.

2. Khi sort và không tô chọn dòng tiêu đề, phải đánh dấu vào ô "My data range has No header row", nếu không, Excel lấy dòng dữ liệu thứ nhất làm tiêu đề. Dòng đó không được sort nên dù là XXXX cũng nằm trên chữ AAA (ascending)
Và đối với hàm của ndu, khi tô chọn dữ liệu không bao gồm dòng tiêu đề, phải chọn False
 
Lần chỉnh sửa cuối:
Upvote 0
Như vậy có cần thêm cái Boolean để tính toán hay không? Trong khi ngay ban đầu cũng đã chọn khối dữ liệu như vậy?
Tạm gát qua 1 bên cái hàm Filter này, chỉ xin hỏi: Ý BẠN MUỐN SAO?
Có phải bạn muốn rằng: Nếu HasTitle = True thì lấy nguyên dữ liệu, ngược lại, HasTitle = False thì Offset dữ liệu xuống 1 dòng?
Nếu sửa lại hàm theo ý của bạn thì cùng lắm hàm này chỉ phục vụ cho có 1 mình bạn mà không có tính tổng quát... Lý do vì bạn mặc định rằng dữ liệu của bạn lúc nào cũng có tiêu đề
Đặt trường hợp dữ liệu của ai đó không có tiêu đề, vậy sẽ dùng hàm thế nào đây? Khi ấy dù HasTitle có = TRUE hay FALSE đều sai tất:
-----------------------
Tôi viết hàm này để xài tổng quát cho mọi dữ liệu (dựa trên cách vận hành của Sort)... Nếu vì phục vụ riêng cho công việc, bạn hãy tự mình sửa lại cho đúng ý mình thôi
 
Upvote 0
Tạm gát qua 1 bên cái hàm Filter này, chỉ xin hỏi: Ý BẠN MUỐN SAO?
Có phải bạn muốn rằng: Nếu HasTitle = True thì lấy nguyên dữ liệu, ngược lại, HasTitle = False thì Offset dữ liệu xuống 1 dòng?
Nếu sửa lại hàm theo ý của bạn thì cùng lắm hàm này chỉ phục vụ cho có 1 mình bạn mà không có tính tổng quát... Lý do vì bạn mặc định rằng dữ liệu của bạn lúc nào cũng có tiêu đề
Đặt trường hợp dữ liệu của ai đó không có tiêu đề, vậy sẽ dùng hàm thế nào đây? Khi ấy dù HasTitle có = TRUE hay FALSE đều sai tất:
-----------------------
Tôi viết hàm này để xài tổng quát cho mọi dữ liệu (dựa trên cách vận hành của Sort)... Nếu vì phục vụ riêng cho công việc, bạn hãy tự mình sửa lại cho đúng ý mình thôi

Không không, ý em là xem lại có thừa hay không khi ta chọn vùng dữ liệu, bao gồm tiêu đề và không tiêu đề.

Trên góc độ người dùng thì:

1) Nếu CSDL không có tiêu đề thì đương nhiên người dùng chọn tất cả.

2) Nếu CSDL có tiêu đề:

2.1) Muốn không lấy tiêu đề thì xuống 1 dòng.

2.2) Nếu có tiêu đề thì chọn đủ. Ở đây lại phát sinh: Nếu tiêu đề không trùng với dữ liệu thì OK, nếu trùng với dữ liệu thì bị xử lý luôn.

==> Như vậy, em đã hoàn toàn hiểu mục đích của Thầy NDU khi đặt cái TIÊU ĐỀ vào rồi.

Em không thắc mắc gì nữa về vụ này nữa!

Cám ơn Thầy NDU và Sư phụ PTM nhiều!
 
Upvote 0
Không không, ý em là xem lại có thừa hay không khi ta chọn vùng dữ liệu, bao gồm tiêu đề và không tiêu đề.

Trên góc độ người dùng thì:

1) Nếu CSDL không có tiêu đề thì đương nhiên người dùng chọn tất cả.

2) Nếu CSDL có tiêu đề:

2.1) Muốn không lấy tiêu đề thì xuống 1 dòng.

2.2) Nếu có tiêu đề thì chọn đủ. Ở đây lại phát sinh: Nếu tiêu đề không trùng với dữ liệu thì OK, nếu trùng với dữ liệu thì bị xử lý luôn.

==> Như vậy, em đã hoàn toàn hiểu mục đích của Thầy NDU khi đặt cái TIÊU ĐỀ vào rồi.

Em không thắc mắc gì nữa về vụ này nữa!

Cám ơn Thầy NDU và Sư phụ PTM nhiều!
Xin nói thêm
- Hàm này không chỉ dùng trên Range mà còn cho mọi Array... Bạn có từng nghĩ đến việc Filter dữ liệu trên ComboBox hoặc ListBox không? Giống từ điển ấy ---> Nó làm gì có tiêu đề
- Nếu gọi là THỪA thì thằng Microsoft cũng phải xem lại chức năng Sort và Remove Duplicate
-----------------------------
Nói chung, tôi đã nghiên cứu rất kỹ, thí nghiệm rất kỹ mới viết hàm này và tin rằng nó đã hoạt động hợp logic
Cái mà chúng ta cần nghiên cứu cải tiến đối với hàm này không phải ở mấy cái tham số mà nên xem liệu nó có hoạt động đúng trên 1 điều kiện đặc biết nào đó không
 
Upvote 0
Đầu tiên sửa code lại 1 chút
Đoạn If Chk Then sửa thành If Chk And FindStr <> "" Then
1> Lấy giá trị rổng, điều kiện là: cứ để trống bình thường
2> Lấy giá trị <> rổng, điều kiện là:: [\W
----------------------
Bạn bôi đen chữ Like trong code, bấm F1 xem help để biết thêm chi tiết
(Nói thật, code này cũng khá hoàn chỉnh rồi nhưng tôi vẫn chưa hài lòng lắm ---> Các bạn có điều kiện nghiên cứu hãy cải tiến giúp tôi với)

Làm ơn cho em hỏi, làm thế nảo để lọc loại trừ một điều kiện? Ví dụ như trong điều kiện là loại trừ người có tên B trong cột Tên, thì lấy giá trị tất cả mà không có tên B.

Dựa theo toán tử LIKE, em đã làm như sau:

Arr1 = Filter2DArray(sArray1, 1, "[!B", False)

Thì tất cả các tên có chứa chữ B bị loại khỏi mảng

Nếu em muốn loại trừ số 1000 ra khỏi mảng em làm như sau:

Arr1 = Filter2DArray(sArray1, 2, "[!1000", False)

Kết quả lại cho tất cả các số nào có 1 đứng đầu sẽ bị loại.

Vậy muốn lọc đúng như ý muốn thì phải làm sao ạ?
 
Upvote 0
Làm ơn cho em hỏi, làm thế nảo để lọc loại trừ một điều kiện? Ví dụ như trong điều kiện là loại trừ người có tên B trong cột Tên, thì lấy giá trị tất cả mà không có tên B.

Dựa theo toán tử LIKE, em đã làm như sau:

Arr1 = Filter2DArray(sArray1, 1, "[!B", False)

Thì tất cả các tên có chứa chữ B bị loại khỏi mảng

Nếu em muốn loại trừ số 1000 ra khỏi mảng em làm như sau:

Arr1 = Filter2DArray(sArray1, 2, "[!1000", False)

Kết quả lại cho tất cả các số nào có 1 đứng đầu sẽ bị loại.

Vậy muốn lọc đúng như ý muốn thì phải làm sao ạ?

Trả lời sơ bộ thế này:
Arr1 = Filter2DArray(sArray1, 2, "<>1000", False)
Nói thêm:
- Với dữ liệu dạng chuổi, ta so sánh theo toán tử LIKE
- Với dữ liệu dạng số, ta so sánh bằng các toán tử "=", ">", "<", "<>" ... vân vân
 
Upvote 0
Trả lời sơ bộ thế này:
Arr1 = Filter2DArray(sArray1, 2, "<>1000", False)
Nói thêm:
- Với dữ liệu dạng chuổi, ta so sánh theo toán tử LIKE
- Với dữ liệu dạng số, ta so sánh bằng các toán tử "=", ">", "<", "<>" ... vân vân

Với dữ liệu dạng chuỗi thì không thể so sánh được ạ! Vậy làm sao với dạng chuỗi?
 
Upvote 0
Nghĩa cho file lên đi... Tôi chưa hình dung được ý của bạn

Với File gửi lên, em làm thử 2 vấn đề:

Mã:
Sub Test()
    Dim MyArr
    Sheet1.[K:P].ClearContents
    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [COLOR=#ff0000][B]"<>Hà"[/B][/COLOR], True)
    If IsArray(MyArr) Then Sheet1.[K1].Resize(UBound(MyArr, 1), 6) = MyArr
End Sub
Với thủ tục này kết quả không lọc gì cả!

Mã:
Sub Test2()
    Dim MyArr
    Sheet1.[K:P].ClearContents
    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [B][COLOR=#ff0000]"[!Hà"[/COLOR][/B], True)
    If IsArray(MyArr) Then Sheet1.[K1].Resize(UBound(MyArr, 1), 6) = MyArr
End Sub
Với thủ tục này, những tên nào có vần H đầu tiên là bị loại trừ luôn!
 

File đính kèm

Upvote 0
Với File gửi lên, em làm thử 2 vấn đề:

Mã:
Sub Test()
    Dim MyArr
    Sheet1.[K:P].ClearContents
    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [COLOR=#ff0000][B]"<>Hà"[/B][/COLOR], True)
    If IsArray(MyArr) Then Sheet1.[K1].Resize(UBound(MyArr, 1), 6) = MyArr
End Sub
Với thủ tục này kết quả không lọc gì cả!

Mã:
Sub Test2()
    Dim MyArr
    Sheet1.[K:P].ClearContents
    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [B][COLOR=#ff0000]"[!Hà"[/COLOR][/B], True)
    If IsArray(MyArr) Then Sheet1.[K1].Resize(UBound(MyArr, 1), 6) = MyArr
End Sub
Với thủ tục này, những tên nào có vần H đầu tiên là bị loại trừ luôn!
Vầy thử xem:
MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, "?[!Hà", True)
 
Upvote 0
Vẫn chưa chắc ăn Thầy ơi, thử với chữ Hoàng thì thay vì loại có 2 chữ nó loại rất nhiều luôn!
Toán tử LIKE nó vậy nên khi dùng phải uyển chuyên
Thay vì viết "?[!Hoàng" thì nên viết là "?[!Ho"
Nói chung, với toán tử LIKE thì sẽ không có cách nào hoàn hảo để Filter theo kiểu <> "gì gì đó" đâu (trừ phi viết lại toàn bộ code theo 1 ý đồ riêng)
 
Upvote 0
Toán tử LIKE nó vậy nên khi dùng phải uyển chuyên
Thay vì viết "?[!Hoàng" thì nên viết là "?[!Ho"
Nói chung, với toán tử LIKE thì sẽ không có cách nào hoàn hảo để Filter theo kiểu <> "gì gì đó" đâu (trừ phi viết lại toàn bộ code theo 1 ý đồ riêng)
Vậy Thầy có thể viết hàm đó với ký hiệu la @ chẳng hạn làm hàm bổ trợ rồi ghép thêm điều kiện vào hàm này có được không ạ?
Cám ơn Thầy!
 
Upvote 0
Vậy Thầy có thể viết hàm đó với ký hiệu la @ chẳng hạn làm hàm bổ trợ rồi ghép thêm điều kiện vào hàm này có được không ạ?
Cám ơn Thầy!
Cái đó dễ mà
Chẳng hạn sửa chổ này:
PHP:
For i = LBound(tmpArr, 1) - HasTitle To UBound(tmpArr, 1)
  If Chk Then
    TmpVal = CDbl(tmpArr(i, ColIndex))
    If Evaluate(TmpVal & FindStr) Then Dic.Add i, ""
  Else
    If UCase(tmpArr(i, ColIndex)) Like UCase(FindStr) Then Dic.Add i, ""
  End If
Next
Thành:
PHP:
For i = LBound(tmpArr, 1) - HasTitle To UBound(tmpArr, 1)
  If Chk Then
    TmpVal = CDbl(tmpArr(i, ColIndex))
    If Evaluate(TmpVal & FindStr) Then Dic.Add i, ""
  Else
    If Left(FindStr, 1) = "!" Then
      If Not (UCase(tmpArr(i, ColIndex)) Like UCase(Mid(FindStr, 2, Len(FindStr)))) Then Dic.Add i, ""
    Else
      If UCase(tmpArr(i, ColIndex)) Like UCase(FindStr) Then Dic.Add i, ""
    End If
  End If
Next
Từ đây nếu bạn viết Filter2DArray(Sheet1.[A1:F29].Value, 1, "!Hà", True) có nghĩa là lọc "<>Hà"
 
Upvote 0
Cái đó dễ mà
Chẳng hạn sửa chổ này:
.................................................
Từ đây nếu bạn viết Filter2DArray(Sheet1.[A1:F29].Value, 1, "!Hà", True) có nghĩa là lọc "<>Hà"

Em đã kiểm tra rất kỹ! Rất chính xác! Cám ơn Thầy rất nhiều!

Một câu hỏi nữa để hiểu hết toàn bộ chức năng của hàm này là, nếu lọc dạng ngày tháng năm thì toán tử >, <, =, <> sẽ được áp dụng như thế nào?
 
Upvote 0
Em đã kiểm tra rất kỹ! Rất chính xác! Cám ơn Thầy rất nhiều!

Một câu hỏi nữa để hiểu hết toàn bộ chức năng của hàm này là, nếu lọc dạng ngày tháng năm thì toán tử >, <, =, <> sẽ được áp dụng như thế nào?
Thì gõ bình thường thôi, chẳng hạn Filter2DArray(sArray ,4, ">Date(2011,5,1)", FALSE)
 
Upvote 0
Hàm Filter2DArray, tác giả ndu96081631:

Em xin cập nhật, tổng hợp lại toàn bộ hàm Filter2DArray của Thầy và cách sử dụng:

PHP:
Function Filter2DArray(ByVal sArray, ByVal ColIndex As Long, ByVal FindStr As String, ByVal HasTitle As Boolean)
    Dim TmpArr, i As Long, j As Long, Arr, Dic, TmpStr, Tmp, Chk As Boolean, TmpVal As Double
    On Error Resume Next
    Set Dic = CreateObject("Scripting.Dictionary")
        TmpArr = sArray
        ColIndex = ColIndex + LBound(TmpArr, 2) - 1
        Chk = (InStr("><=", Left(FindStr, 1)) > 0)
    For i = LBound(TmpArr, 1) - HasTitle To UBound(TmpArr, 1)
        If Chk And FindStr <> "" Then
            TmpVal = CDbl(TmpArr(i, ColIndex))
            If Evaluate(TmpVal & FindStr) Then Dic.Add i, ""
        Else
            If Left(FindStr, 1) = "!" Then
                If Not (UCase(TmpArr(i, ColIndex)) Like UCase(Mid(FindStr, 2, Len(FindStr)))) Then Dic.Add i, ""
            Else
                If UCase(TmpArr(i, ColIndex)) Like UCase(FindStr) Then Dic.Add i, ""
            End If
        End If
    Next
    If Dic.Count > 0 Then
        Tmp = Dic.Keys
        ReDim Arr(LBound(TmpArr, 1) To UBound(Tmp) + LBound(TmpArr, 1) - HasTitle, LBound(TmpArr, 2) To UBound(TmpArr, 2))
            For i = LBound(TmpArr, 1) - HasTitle To UBound(Tmp) + LBound(TmpArr, 1) - HasTitle
                For j = LBound(TmpArr, 2) To UBound(TmpArr, 2)
                    Arr(i, j) = TmpArr(Tmp(i - LBound(TmpArr, 1) + HasTitle), j)
                Next
            Next
        If HasTitle Then
            For j = LBound(TmpArr, 2) To UBound(TmpArr, 2)
                Arr(LBound(TmpArr, 1), j) = TmpArr(LBound(TmpArr, 1), j)
            Next
        End If
    End If
    Filter2DArray = Arr
End Function

Cách sử dụng:

1) Lọc xử lý dạng chuỗi:
Mã:
Sub Loc_Xu_Ly_Chuoi()
    Dim MyArr
    Sheet1.[K:P].ClearContents
'    [COLOR=#006400]'Lọc loại trừ chuỗi là rỗng:[/COLOR]
'        MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [COLOR=#0000cd][B]"["[/B][/COLOR], True)
'    [COLOR=#006400]'Lọc chỉ lấy chuỗi là rỗng:[/COLOR]
'        MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [B][COLOR=#0000cd]""[/COLOR][/B], True)
'    [COLOR=#006400]'Lọc lấy chuỗi tuyệt đối:[/COLOR]
'        MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [B][COLOR=#0000cd]"Sang"[/COLOR][/B], True)
'    [COLOR=#006400]'Lọc loại trừ chuỗi tuyệt đối:[/COLOR]
'        MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [B][COLOR=#0000cd]"!Sang"[/COLOR][/B], True)
'    [COLOR=#006400]'Lọc loại trừ chuỗi tương đối, ngược lại, lấy chuỗi tương đối chỉ cần bỏ dấu chấm thang (!):[/COLOR]
'        MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [COLOR=#0000cd][B]"!H*"[/B][/COLOR], True)
'        MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [COLOR=#0000cd][B]"!*n*"[/B][/COLOR], True)
'        MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [COLOR=#0000cd][B]"!H?"[/B][/COLOR], True)
        MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [COLOR=#0000cd][B]"!H?a"[/B][/COLOR], True)
    If IsArray(MyArr) Then Sheet1.[K1].Resize(UBound(MyArr, 1), 6) = MyArr
End Sub

2) Lọc xử lý dạng số:
Mã:
Sub Loc_Xu_Ly_So()
    Dim MyArr
    Sheet1.[K:P].ClearContents
'    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 2, [B][COLOR=#0000cd]">5"[/COLOR][/B], True)
'    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 2, [COLOR=#0000cd][B]">=5"[/B][/COLOR], True)
'    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 2, [COLOR=#0000cd][B]"<>5"[/B][/COLOR], True)
'    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 2, [B][COLOR=#0000cd]"<5"[/COLOR][/B], True)
'    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 2, [COLOR=#0000cd][B]"<=5"[/B][/COLOR], True)
    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 2, [B][COLOR=#0000cd]"=5"[/COLOR][/B], True)
    If IsArray(MyArr) Then Sheet1.[K1].Resize(UBound(MyArr, 1), 6) = MyArr
End Sub

3) Lọc xử lý dạng ngày tháng:
Mã:
Sub Loc_Xu_Ly_Ngay_Thang()
    Dim MyArr
    Sheet1.[K:P].ClearContents
    [COLOR=#006400]'Bắt buộc ghi cấu trúc phải có dạng:[/COLOR] [COLOR=#ff0000][B]Date(y,m,d)[/B][/COLOR]
'    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 3, [COLOR=#0000cd][B]">Date(2011,11,29)"[/B][/COLOR], True)
'    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 3, [B][COLOR=#0000cd]">=Date(2011,11,29)"[/COLOR][/B], True)
'    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 3, [B][COLOR=#0000cd]"<>Date(2011,11,29)"[/COLOR][/B], True)
'    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 3, [B][COLOR=#0000cd]"<Date(2011,11,29)"[/COLOR][/B], True)
'    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 3, [COLOR=#0000cd][B]"<=Date(2011,11,29)"[/B][/COLOR], True)
    MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 3, [B][COLOR=#0000cd]"=Date(2011,11,29)"[/COLOR][/B], True)
    If IsArray(MyArr) Then Sheet1.[K1].Resize(UBound(MyArr, 1), 6) = MyArr
End Sub

Cám ơn Thầy ndu96081631 rất nhiều!
 

File đính kèm

Upvote 0
Em xin cập nhật, tổng hợp lại toàn bộ hàm Filter2DArray của Thầy và cách sử dụng:
PHP:
'    'Lọc lấy chuỗi tuyệt đối:
'        MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, "Sang", True)
'    'Lọc loại trừ chuỗi tuyệt đối:
'        MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, "!Sang", True)
Trường hợp trên lọc lấy (loại trừ) chuỗi tuyệt đối 1 điều kiện. Vậy xin hỏi các anh chị trường hợp lọc lấy (loại trừ) chuỗi tuyệt đối với 2 điều kiện thì sao?
 
Lần chỉnh sửa cuối:
Upvote 0
Trường hợp trên lọc lấy (loại trừ) chuỗi tuyệt đối 1 điều kiện. Vậy xin hỏi các anh chị trường hợp lọc lấy (loại trừ) chuỗi tuyệt đối với 2 điều kiện thì sao?

Dĩ nhiên hàm này Thầy ndu96081631 viết không thể nào bằng AutoFilter của Excel mà có thể lọc một lúc nhiều điều kiện (chắc có lẽ sau này Thầy sẽ cải tiến thêm). Tuy nhiên, nếu linh hoạt trong trường hợp này thì không có gì là khó cả, chúng ta làm như sau:

Điều kiện loại trừ là SANG và HOÀNG thì ta lần lượt lọc từng cái trước:

Mã:
MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [COLOR=#0000ff][B]"!Sang"[/B][/COLOR], True)


Sau đó, mình lại tiếp tục với thủ tục thứ hai, nhưng lần này lọc từ MyArr:

Mã:
MyArr = Filter2DArray([COLOR=#ff0000][B]MyArr [/B][/COLOR], 1, [B][COLOR=#0000ff]"!Hoàng"[/COLOR][/B], True)

Sau đó mình gán MyArr lên sheet hay source nào đó thôi.

Nói tóm lại, muốn lọc nhiều điều kiện ta cứ lần lượt lọc cái A rồi lấy giá trị đã lọc và lọc tiếp, cho dù nhiều điều kiện mình vẫn làm thế, với hàm này cũng không mất thời gian đâu.
 
Upvote 0
Dĩ nhiên hàm này Thầy ndu96081631 viết không thể nào bằng AutoFilter của Excel mà có thể lọc một lúc nhiều điều kiện (chắc có lẽ sau này Thầy sẽ cải tiến thêm). Tuy nhiên, nếu linh hoạt trong trường hợp này thì không có gì là khó cả, chúng ta làm như sau:

Điều kiện loại trừ là SANG và HOÀNG thì ta lần lượt lọc từng cái trước:

Mã:
MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, [COLOR=#0000ff][B]"!Sang"[/B][/COLOR], True)


Sau đó, mình lại tiếp tục với thủ tục thứ hai, nhưng lần này lọc từ MyArr:

Mã:
MyArr = Filter2DArray([COLOR=#ff0000][B]MyArr [/B][/COLOR], 1, [B][COLOR=#0000ff]"!Hoàng"[/COLOR][/B], True)

Sau đó mình gán MyArr lên sheet hay source nào đó thôi.

Nói tóm lại, muốn lọc nhiều điều kiện ta cứ lần lượt lọc cái A rồi lấy giá trị đã lọc và lọc tiếp, cho dù nhiều điều kiện mình vẫn làm thế, với hàm này cũng không mất thời gian đâu.
Cảm ơn anh rất nhiều, em thấy hàm này rất hay, tốc độ chạy nhanh so với AutoFilter nên em muốn tiến xa hơn, thậm chí em đang muốn lọc duy nhất nữa, nhưng tự làm mà khả năng hạn chế. Với giải pháp như anh nói tạm thời chấp nhận được (2 điều kiện thì lọc lại lần 2) em thấy tốc độ vẫn nhanh. Mong muốn các anh cải tiến thêm thì quá tốt. Cảm ơn hàm của Thầy ndu96081631 và cải tiến của anh minhthien321
 
Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn anh rất nhiều, em thấy hàm này rất hay, tốc độ chạy nhanh so với AutoFilter nên em muốn tiến xa hơn, thậm chí em đang muốn lọc duy nhất nữa, nhưng tự làm mà khả năng hạn chế. Với giải pháp như anh nói tạm thời chấp nhận được (2 điều kiện thì lọc lại lần 2) em thấy tốc độ vẫn nhanh. Mong muốn các anh cải tiến thêm thì quá tốt. Cảm ơn hàm của Thầy ndu96081631 và cải tiến của anh minhthien321


Nếu bạn muốn lọc duy nhất, cũng là hàm được viết bởi Thầy ndu96081631, bạn xem tại đường dẫn dưới đây:

http://www.giaiphapexcel.com/forum/...mắc-về-hàm-UDF-UniqueList&p=338234#post338234
 
Upvote 0
Nếu bạn muốn lọc duy nhất, cũng là hàm được viết bởi Thầy ndu96081631, bạn xem tại đường dẫn dưới đây:

http://www.giaiphapexcel.com/forum/...mắc-về-hàm-UDF-UniqueList&p=338234#post338234

Tôi chỉ muốn lưu ý một điểm. Hàm của bạn ndu96081631 rất hay nhưng chưa lường được tình huống về chuỗi. Ta không thể mặc định là dữ liệu của người dùng sẽ như ta nghĩ. Vd. tôi có danh sách do đồng nghiệp đã thôi việc để lại và tôi bổ sung rất nhiều. Hoặc 1 đoạn tôi lấy từ nguồn ngoài. Người ta viết "Hà" bằng Unikey và chọn Unicode (dựng sẵn) trong khi tôi chưa bao giừ dùng Unikey (dùng chơi để biết thì có). Nếu tôi dùng bàn phím của Windows gõ vào bảng tính "Hà" thì với code:
MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, "Hà", True)
thì
UCase(TmpArr(i, ColIndex)) Like UCase(FindStr) trả về FALSE mặc dù ở bảng tính ở chỗ đó có "Hà"
Đơn giản là "người ta" gõ "Hà" dựng sẵn (4 bai) trong khi "Hà" tôi gõ là Unicode TỔ HỢP (6 bai). Lý do là Windows tuy hỗ trợ cả 2 loại Unicode nhưng bản thân Windows dùng Unicode tổ hợp.
Bạn thử mở notepad --> gõ "à" --> ghi lại ở dạng unicode --> mở tập tin vừa ghi trong Hex Editor bạn sẽ thấy "à" có 2 WORD - 4 bai $0300, $0061 ("à" là tổ hợp của 2 ký tự là "a" và ký tự dấu huyền - $0300) trong khi "à" dựng sẵn chỉ có 2 bai - 1 WORD là $00E0
Ngoài ra hàm của bạn ndu96081631 là đẹp rồi. Nhiều khi bạn dùng thấy không như ý là do bạn chưa rành về viết mask (FindStr) mà thôi. Nó có qui tắc rõ ràng, sử dụng một số ký tự (vd. *, ? ...) nhất định và những ký tự đó có nghĩa rõ ràng. Khi bạn thấy chưa như ý tức là bạn viết mask sai, tức mask không làm đúng cái mà bạn muốn.
 
Upvote 0
Dĩ nhiên hàm này Thầy ndu96081631 viết không thể nào bằng AutoFilter của Excel mà có thể lọc một lúc nhiều điều kiện (chắc có lẽ sau này Thầy sẽ cải tiến thêm). Tuy nhiên, nếu linh hoạt trong trường hợp này thì không có gì là khó cả, chúng ta làm như sau:

Bạn ndu96081631 tặng mọi người mã nguồn thì chắc cũng cho phép sửa để dùng theo yêu cầu. Nếu bạn biết chút về lập trình, đọc code hiểu thì có khó gì? Thêm một FindStr nữa vào. Rồi những chỗ như:
If UCase(TmpArr(i, ColIndex)) Like UCase(FindStr) Then Dic.Add i, ""
sửa thành
If UCase(TmpArr(i, ColIndex)) Like UCase(FindStr1) or _
UCase(TmpArr(i, ColIndex)) Like UCase(FindStr2) Then Dic.Add i, ""
Gọi:
MyArr = Filter2DArray(Sheet1.[A1:F29].Value, 1, "Sang", "Hoàng", True)
Hoặc bạn sửa thành: không phải 1 mask mà là một danh sách mask?
Đại loại là thế, tôi chỉ đọc lướt qua để hiểu thôi chứ không định chỉnh sửa gì.
 
Upvote 0
Một chủ đề rất hay, cảm ơn bác Trọng Nghĩa nhé, em cũng đang cần tìm cái này.
 
Upvote 0
Lọc với 2 điều kiện kiểu "A và B" - "A and B" thì dễ rồi vì chỉ cần gọi hàm 2 lần. Vậy xin hỏi các anh chị trường hợp lọc với điều kiện kiểu "A hoặc B" - "A or B" thì sao?
 
Upvote 0
PHP:
Function Filter2DArray(ByVal sArray, ByVal ColIndex As Long, ByVal FindStr As String, ByVal HasTitle As Boolean)
  Dim tmpArr, i As Long, j As Long, Arr, Dic, TmpStr, Tmp, Chk As Boolean, TmpVal As Double
  On Error Resume Next
  Set Dic = CreateObject("Scripting.Dictionary")
  tmpArr = sArray
  ColIndex = ColIndex + LBound(tmpArr, 2) - 1
  Chk = (InStr("><=", Left(FindStr, 1)) > 0)
  For i = LBound(tmpArr, 1) - HasTitle To UBound(tmpArr, 1)
    If Chk And FindStr <> "" Then
      TmpVal = CDbl(tmpArr(i, ColIndex))
      If Evaluate(TmpVal & FindStr) Then Dic.Add i, ""
    Else
      If Left(FindStr, 1) = "!" Then
        If Not (UCase(tmpArr(i, ColIndex)) Like UCase(Mid(FindStr, 2, Len(FindStr)))) Then Dic.Add i, ""
      Else
        If UCase(tmpArr(i, ColIndex)) Like UCase(FindStr) Then Dic.Add i, ""
      End If
    End If
  Next
  If Dic.Count > 0 Then
    Tmp = Dic.Keys
    ReDim Arr(LBound(tmpArr, 1) To UBound(Tmp) + LBound(tmpArr, 1) - HasTitle, LBound(tmpArr, 2) To UBound(tmpArr, 2))
    For i = LBound(tmpArr, 1) - HasTitle To UBound(Tmp) + LBound(tmpArr, 1) - HasTitle
      For j = LBound(tmpArr, 2) To UBound(tmpArr, 2)
        Arr(i, j) = tmpArr(Tmp(i - LBound(tmpArr, 1) + HasTitle), j)
      Next
    Next
    If HasTitle Then
      For j = LBound(tmpArr, 2) To UBound(tmpArr, 2)
        Arr(LBound(tmpArr, 1), j) = tmpArr(LBound(tmpArr, 1), j)
      Next
    End If
  End If
  Filter2DArray = Arr
End Function

Tôi đã định góp ý về hàm Filter2DArray từ lâu nhưng chưa có dịp.
Trước hết phải nói rằng hàm Filter2DArray rất hay về ý tưởng. Cũng vì nó hay nên đáng bỏ thời gian ra để hoàn thiện nó.
Ý tưởng thì rõ rồi, còn chuyện code cụ thể như thế nào thì tất nhiên có nhiều cách. Cái tôi muốn góp ý ở đây là dòng mầu đỏ: TmpVal = CDbl(tmpArr(i, ColIndex))
Ai cũng biết là tùy dữ liệu mà việc chuyển đổi thành công hay thất bại. Chính vì thế mà ta phải "bẫy lỗi". Nhưng có lúc chỉ cần bẫy lỗi để "qua được lỗi", "lờ lỗi đi", nhưng có lúc nếu ta không phục vụ trường hợp lỗi thì nó sẽ ảnh hưởng tới các kết quả về sau. Ở đây ta có th thứ hai.
Dữ liệu trong cuộc sống có muôn vàn, khó có thể liệt kê ra được. Nhưng chắc chắn nó có thể có dòng trống, hoặc dữ liệu trong cột lọc không là một kiểu duy nhất. Trường hợp dòng trống thì ngay trong chủ đề này ta truyền vào hàm Filter2DArray một mảng có vài dòng đầu trống. Trường hợp dữ liệu nhiều kiểu thì tôi bịa ra vd. như thế này: Cột A chứa họ và tên nhân viên. Cột B là số ngày nghỉ không phép: 0, 1, 2, 3, 4, "nhieu hon 4" (tức 5, 6 = mất phần thưởng), "nhieu hon 6" (cảnh cáo)
Với vd. như trên thì sau khi nhấn nút "Lọc" ta sẽ có kết quả như "hình loc.jpg", tức thừa 3 dòng cuối.

View attachment 84255

Tại sao? Ta hãy nhìn vào dòng mầu đỏ. Ở vòng lặp đầu tiên (th tổng quát là ở vòng lặp thứ n) ta có TmpVal = 2 - thỏa điều kiện nên ta thêm vào Dic: If Evaluate(TmpVal & FindStr) Then Dic.Add i, ""
Tới vòng thứ 2, 3, 4 thì đều gặp lỗi convert nhưng ta đã bẫy lỗi nên code "đi tiếp" tới dòng
Mã:
If Evaluate(TmpVal & FindStr) Then Dic.Add i, ""
Do convert bị lỗi nên giá trị của biến TmpVal không được thay đổi, tức trong vòng lặp 2, 3, 4 thì vẫn có TmpVal = 2, tức thỏa điều kiện nên dòng 2, 3, 4 vẫn được thêm vào từ điển.
Để code hoạt động đúng thì trong th này không được "lờ đi" lỗi sẩy ra. Phải có đoạn code phục vụ trường hợp lỗi. Tức sau dòng mầu đỏ ta kiểu tra xem có lỗi hay không, nếu có thì "xóa" lỗi đi.
Mã:
                 If Err.Number = 0 Then 
                     If Evaluate(TmpVal & FindStr) Then Dic.Add i, ""
                 Else
                     Err.Clear
                 End If
Ngoài ra tôi còn đề nghị thay
Mã:
     For i = LBound(TmpArr, 1) - HasTitle To UBound(Tmp) + LBound(TmpArr, 1) - HasTitle
        For j = LBound(TmpArr, 2) To UBound(TmpArr, 2)
          Arr(i, j) = TmpArr(Tmp(i - LBound(TmpArr, 1) + HasTitle), j)
        Next
     Next
bằng
Mã:
                 For i = LBound(TmpArr, 1) - HasTitle To UBound(Tmp) + LBound(TmpArr, 1) - HasTitle
                     currRow = i - LBound(TmpArr, 1) + HasTitle
                     For j = LBound(TmpArr, 2) To UBound(TmpArr, 2)
                          Arr(i, j) = TmpArr(Tmp(currRow), j)
                     Next
                 Next
Vì sao? Vì biểu thức i - LBound(TmpArr, 1) + HasTitle chỉ phụ thuộc vào i nên trong vòng lặp thứ hai thì giá trị của nó không thay đổi, vậy thay vì tính giá trị đó j lần thì chỉ tính 1 lần (trước vòng lặp) và sau đó đọc từ biến vào.
Thậm chí tôi còn khuyến cáo là trong code
Mã:
     If HasTitle Then
        For j = LBound(TmpArr, 2) To UBound(TmpArr, 2)
           Arr(LBound(TmpArr, 1), j) = TmpArr(LBound(TmpArr, 1), j)
        Next
     End If
Ta "đọc" LBound(TmpArr, 1) vào biến rồi sau đó dùng biến. Vì đọc từ biến vào bao giờ cũng nhanh hơn gọi hàm (trong th hàm này thì nhanh hơn chút chút thôi) - tiết kiệm cho bộ vi xử lý rất nhiều thao tác, tức tiết kiệm được nhiều "nhịp" đồng hồ.
--------------------
Về hàm Filter2DArray thì nếu ta có 2 điều kiện được liên kết với nhau bởi toán tử AND thì chỉ cần gọi hàm 2 lần - lần gọi thứ hai thì truyền mảng trả về từ lần gọi thứ nhất. Nhưng nếu 2 đk được liên kết bởi toán tử OR thì không thể làm được như thế. Tôi mạn phép sửa code hàm Filter2DArray như sau, mời mọi người tham khảo. Tôi chú thích rất tỉ mỉ để các bạn mới làm quen hiểu ngay được mỗi vấn đề.
Mã:
Function Filter2DArray(ByVal sArray, ByVal ColIndex As Long, ByVal FindStr1 As String, ByVal HasTitle As Boolean, _
    Optional ByVal FindStr2, Optional ByVal arg_and As Boolean = True)
'    sArray là mảng - range chứa các giá trị cần lọc
'    ColIndex là chỉ số cột mà các giá trị ở đấy sẽ được lọc. Chỉ số này được tính từ 1 bất kể chỉ số sArray được tính từ bao nhiêu.
'    vd. ta truyền mảng sArray thực chất là mảng sArray(4 to 35, 5 to 10) mà ta muốn lọc theo cột thứ 2 thì ColIndex = 2
'    FindStr1(2) là mask để kiểm tra xem có khớp với các giá trị trong cột ColIndex hay không
'    Nếu khớp thì toàn bộ dòng có chứa giá trị khớp đó sẽ được trả về
'    Có 3 loại MASK
'    1. loại "><=xyz" - xyz là các chữ số
'    2. loại "!xyz" - lấy các dòng mà ở cột ColIndex không có cụm ký tự "xyz", tức loại các dòng mà ở cột ColIndex có chứa "xyz"
'    3. loại "xyz" - lấy các dòng mà ở cột ColIndex có cụm ký tự "xyz"
'    HasTitle - thông báo là mảng nhập vào có chứa tiêu đề ở dòng đầu tiên (TRUE) hoặc không chứa (FALSE)
    Dim TmpArr, i As Long, j As Long, Arr, Dic, TmpStr, Tmp, Chk As Boolean, TmpVal As Double, sArr As String, sFind As String, res As Boolean
    Dim currRow As Long
    On Error Resume Next
    Set Dic = CreateObject("Scripting.Dictionary")
'          sao dữ liệu từ sArray sang TmpArr
        TmpArr = sArray
'         ColIndex là chỉ số cột tìm kiếm trong sArray tính từ 1, cột đó trong TmpArr có chỉ số:
        ColIndex = ColIndex + LBound(TmpArr, 2) - 1
'         kiểm tra xem ký tự đầu tiên trong mask FindStr1 có phải là "<", ">" hay "=" không. Nếu có thì mask là loại 1, tức ta tìm và lấy
'         các dòng có chứa số "abc" thỏa điều kiện abc ><=xyz.
        If FindStr1 <> "" Then
            Chk = InStr("><=", Left(FindStr1, 1)) > 0
            If Not IsMissing(FindStr2) And (FindStr2 <> "") Then Chk = Chk And (InStr("><=", Left(FindStr1, 1)) > 0)
        End If
'         đi từng dòng trong cột lọc ColIndex và lọc lấy dữ liệu
        For i = LBound(TmpArr, 1) - HasTitle To UBound(TmpArr, 1)
            If Chk Then
                ' nếu FindStr1 là dạng ><= xyz thì đọc giá trị tại dòng hiện hành ở cột ColIndex
                TmpVal = CDbl(TmpArr(i, ColIndex))
                ' kiểm tra lỗi vì dữ liệu đầu vào có thể chứa lỗi
                If Err.Number = 0 Then
                    ' và nếu giá trị đó là số và thỏa mãn (TmpVal ><= xyz) thì thêm chỉ số dòng hiện hành (được chọn) vào từ điển
                    res = Evaluate(TmpVal & FindStr1)
                    If Not IsMissing(FindStr2) And (FindStr2 <> "") Then
                        If arg_and Then
                            res = res And Evaluate(TmpVal & FindStr2)
                        Else
                            res = res Or Evaluate(TmpVal & FindStr2)
                        End If
                    End If
                Else
                    Err.Clear
                End If
            Else
'                 neu FindStr1 khong la dang ><= B
'                 nếu FinStr1 không là dạng ><=xyz thì kiểm tra xem ký tự đầu của FindStr1 có phải là "!" hay không, tức xem
'                 FindStr1 có dạng !xyz hay không.
                sArr = UCase(TmpArr(i, ColIndex))
                
                If Left(FindStr1, 1) = "!" Then
'                     FindStr có dạng "!xyz" vậy ta thêm vào từ điển chỉ số dòng hiện hành nếu giá trị ở cột ColIndex không chứa cụm "xyz"
                    res = Not (sArr Like UCase(Mid(FindStr1, 2, Len(FindStr1))))
                Else
'                     FindStr không có dạng "!xyz" vậy ta thêm vào từ điển chỉ số dòng hiện hành nếu giá trị ở cột ColIndex chứa cụm "xyz"
                    res = sArr Like UCase(FindStr1)
                End If
'                nếu có thông số thứ 2
                If Not IsMissing(FindStr2) Then
                    If Left(FindStr2, 1) = "!" Then
'                         FindStr2 có dạng "!xyz" vậy ta thêm vào từ điển chỉ số dòng hiện hành nếu giá trị ở cột ColIndex không chứa cụm "xyz"
                        If arg_and Then
                            res = res And Not (sArr Like UCase(Mid(FindStr2, 2, Len(FindStr2))))
                        Else
                            res = res Or Not (sArr Like UCase(Mid(FindStr2, 2, Len(FindStr2))))
                        End If
                    Else
'                         FindStr2 không có dạng "!xyz" vậy ta thêm vào từ điển chỉ số dòng hiện hành nếu giá trị ở cột ColIndex chứa cụm "xyz"
                        If arg_and Then
                            res = res And (sArr Like UCase(FindStr2))
                        Else
                            res = res Or (sArr Like UCase(FindStr2))
                        End If
                    End If
                End If
            End If
            If res Then Dic.Add i, ""
        Next
'         nếu trong từ điển có dữ liệu là các chỉ số dòng được chọn thì các chỉ số đó là các Key trong mảng Keys
        If Dic.count > 0 Then
            Tmp = Dic.Keys
'             tạo mảng Arr có số dòng bằng số chỉ số dòng được chọn và số cột bằng số côt của mảng nguồn sArray
            ReDim Arr(LBound(TmpArr, 1) To UBound(Tmp) + LBound(TmpArr, 1) - HasTitle, LBound(TmpArr, 2) To UBound(TmpArr, 2))
'                 ghi các dòng của mảng nguồn mà có chỉ số là các phần tử cua Dic.Keys (tức các dòng được lấy) vào mảng Arr
                For i = LBound(TmpArr, 1) - HasTitle To UBound(Tmp) + LBound(TmpArr, 1) - HasTitle
                    currRow = i - LBound(TmpArr, 1) + HasTitle
                    For j = LBound(TmpArr, 2) To UBound(TmpArr, 2)
                        Arr(i, j) = TmpArr(Tmp(currRow), j)
                    Next
                Next
'             nếu mảng nguồn có chứa tiêu đề thì ghi tiêu đề vào mảng Arr ở dòng đầu tiên
            If HasTitle Then
                For j = LBound(TmpArr, 2) To UBound(TmpArr, 2)
                    Arr(LBound(TmpArr, 1), j) = TmpArr(LBound(TmpArr, 1), j)
                Next
            End If
        End If
'         trả về mảng các dòng được chọn - lọc
        Filter2DArray = Arr
End Function
 
Lần chỉnh sửa cuối:
Upvote 0
Mã:
Function Filter2DArray(ByVal sArray, ByVal ColIndex As Long, ByVal FindStr1 As String, ByVal HasTitle As Boolean, _
    Optional ByVal FindStr2, Optional ByVal arg_and As Boolean = True)
...

Thực sự mà nói thì Anh đã giải thích rất cặn kẻ, tuy nhiên để ứng dụng vào Excel để lọc thì em không biết Optional ByVal FindStr2, Optional ByVal arg_and As Boolean = True sẽ sử dụng như thế nào, Anh có thể đưa lên 1 file Excel về các cách lọc mà Anh thêm vào hay không? Cám ơn rất nhiều.
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Thực sự mà nói thì Anh đã giải thích rất cặn kẻ, tuy nhiên để ứng dụng vào Excel để lọc thì em không biết Optional ByVal FindStr2, Optional ByVal arg_and As Boolean = True sẽ sử dụng như thế nào, Anh có thể đưa lên 1 file Excel về các cách lọc mà Anh thêm vào hay không? Cám ơn rất nhiều.

Hàm luôn có 1 đk lọc là FindStr1. Nếu ta chỉ lọc theo 1 đk thì những thông số tùy chọn ta để nguyên, chúng sẽ không được sử dụng. Nếu ta lọc có 2 đk thì nhập đk 2 là FindStr2. Tất nhiên chỉ thế thì chưa đủ vì ta không biết 2 đk đó được kết hợp bởi AND hay OR. Mặc định thì arg_and = TRUE có nghĩa là nếu có 2 đk thì chúng sẽ được kết hợp bởi AND. Tóm lại:
1. Nếu chỉ có 1 đk thì mặc định để nguyên (không nhập)
2. Nếu có 2 đk thì nhập thêm FindStr2. Nếu toán tử là AND thì nhập TRUE hoặc để nguyên mặc định của arg_and. Nếu OR thì nhập arg_and = FALSE.

Hàm trên hỗ trợ tiếng Việt với đk là văn bản và đoạn cần tìm là cùng unicode tổ hợp hoặc cùng là unicode dựng sẵn. Nếu ta nhập đoạn cần tìm bằng dứng sẵn nhưng văn bản của người khác (đối tác?) dùng tổ hợp thì có thể không tìm ra.
Tôi có viết lại hàm dùng:
1. Không dùng LIKE mà dùng RegExp --> pattern đa dạng hơn. VD. có thể dùng [â-ư]
2. Văn bản và đoạn cần tìm tùy ý vì code sẽ convert cả hai sang dựng sẵn.
Tất nhiên nếu làm thế thì code sẽ dài. Nhưng về mặt người dùng thì dài hay ngắn không quan trọng vì user chỉ nhập thông số thôi mà.
 
Lần chỉnh sửa cuối:
Upvote 0
Hàm luôn có 1 đk lọc là FindStr1. Nếu ta chỉ lọc theo 1 đk thì những thông số tùy chọn ta để nguyên, chúng sẽ không được sử dụng. Nếu ta lọc có 2 đk thì nhập đk 2 là FindStr2. Tất nhiên chỉ thế thì chưa đủ vì ta không biết 2 đk đó được kết hợp bởi AND hay OR. Mặc định thì arg_and = TRUE có nghĩa là nếu có 2 đk thì chúng sẽ được kết hợp bởi AND. Tóm lại:
1. Nếu chỉ có 1 đk thì mặc định để nguyên (không nhập)
2. Nếu có 2 đk thì nhập thêm FindStr2. Nếu toán tử là AND thì nhập TRUE hoặc để nguyên mặc định của arg_and. Nếu OR thì nhập arg_and = FALSE.

Hàm trên hỗ trợ tiếng Việt với đk là văn bản và đoạn cần tìm là cùng unicode tổ hợp hoặc cùng là unicode dựng sẵn. Nếu ta nhập đoạn cần tìm bằng dứng sẵn nhưng văn bản của người khác (đối tác?) dùng tổ hợp thì có thể không tìm ra.
Tôi có viết lại hàm dùng:
1. Không dùng LIKE mà dùng RegExp --> pattern đa dạng hơn. VD. có thể dùng [â-ư]
2. Văn bản và đoạn cần tìm tùy ý vì code sẽ convert cả hai sang dựng sẵn.
Tất nhiên nếu làm thế thì code sẽ dài. Nhưng về mặt người dùng thì dài hay ngắn không quan trọng vì user chỉ nhập thông số thôi mà.

Vậy nhờ Anh vui lòng viết tiếp và chia sẻ hàm mới theo hướng của Anh đi ạ, nó rất là hữu ích. Cám ơn Anh rất nhiều.
 
Lần chỉnh sửa cuối:
Upvote 0
Vậy nhờ Anh vui lòng viết tiếp và chia sẻ hàm mới theo hướng của Anh đi ạ, nó rất là hữu ích. Cám ơn Anh rất nhiều.

Theo tôi hàm của ndu sửa chút để lọc với 2 đk là thỏa 99,99% nhu cầu rồi. Cũng chả cần thỏa 0,01% kia làm gì. Vì thực ra để dùng cho hết chức năng thì phải biết về RegExp còn không nếu chỉ dùng pattern đơn giản thì dùng luôn LIKE cho rồi.
Nhưng với code hiện thời thì 2 đk vẫn chưa độc lập với nhau với nghĩa là nếu FindStr1 là lọc theo chuỗi (ngày tháng, số - tức ở đầu có ><=) thì code cho là FindStr2 cũng lọc theo chuỗi (ngày tháng, số). Muốn 2 đk hoàn toàn độc lập, tức FindStr1, FindStr2 có thể lọc theo chuỗi, số mà không phụ thuộc vào nhau - vd. FindStr1 lọc theo chuỗi, FindStr2 lọc theo so sánh số thì cũng chỉ cần sửa code chút ít thôi.

Mã:
Function Filter2DArray(ByVal sArray, ByVal ColIndex As Long, ByVal HasTitle As Boolean, _
    ByVal FindStr1 As String, Optional ByVal FindText1 As Boolean = True, _
    Optional ByVal FindStr2 As String, Optional ByVal FindText2 As Boolean = True, _
    Optional ByVal arg_and As Boolean = True)
'    sArray là mảng - range chứa các giá trị cần lọc
'    ColIndex là chỉ số cột mà các giá trị ở đấy sẽ được lọc. Chỉ số này được tính từ 1 bất kể chỉ số sArray được tính từ bao nhiêu.
'    vd. ta truyền mảng sArray thực chất là mảng sArray(4 to 35, 5 to 10) mà ta muốn lọc theo cột thứ 2 thì ColIndex = 2
'    HasTitle - thông báo là mảng nhập vào có chứa tiêu đề ở dòng đầu tiên (TRUE) hoặc không chứa (FALSE)
'    FindStr1(2) là mẫu để kiểm tra xem có khớp với các giá trị trong cột ColIndex hay không
'    Nếu khớp thì toàn bộ dòng có chứa giá trị khớp đó sẽ được trả về
'    Có 3 loại MẪU
'    1. loại "><=xyz" - xyz là các chữ số, tức ký tự đầu là >, >=, <, <= hoặc =. Khớp khi dòng ở cột ColIndex có giá trị "abc" mà abc ><= xyz
'    2. loại "!xyz" - Khớp khi dòng ở cột ColIndex không có cụm ký tự "xyz"
'    3. loại "xyz" - Khớp khi dòng ở cột ColIndex có cụm ký tự "xyz"
'    FindText1 và FindText2 xác định mẫu là dạng nào. Nếu FindText1 hoặc FindText2 = False thì có nghĩa là FindStr1 hoặc FindStr2
'    là mẫu loại 1 - "><=xyz". Ví dụ nếu FindText1 = TRUE thì nếu FindStr1 có dang "><=xyz" thì nó cũng chỉ là mẫu loại 3 chứ
'    không phải là mẫu loại 1. Điều này cho phép tìm các chuỗi có ký tự đầu là >, < hoặc =
'    nếu có 2 điều kiện thì arg_and cho biết chúng được kết hợp với nhau bởi toán tử nào. arg_and = True có nghĩa toán tử là
'    AND, ngược lại thì là OR
    Dim copyArr, i As Long, j As Long, Arr, rows_found, Number As Double, res As Boolean, tmpres As Boolean
    Dim currRow As Long, FirstRow As Long, Dict As Object
    On Error Resume Next
        Set Dict = CreateObject("Scripting.Dictionary")
'       sao dữ liệu từ sArray sang copyArr
        copyArr = sArray
'        chỉ số dòng đầu trong mảng copyArr
        FirstRow = LBound(copyArr, 1)
        
'         ColIndex là chỉ số cột tìm kiếm trong sArray tính từ 1, cột đó trong copyArr có chỉ số:
        ColIndex = ColIndex + LBound(copyArr, 2) - 1
        
'         đi từng dòng trong cột lọc ColIndex và lọc lấy dữ liệu
        For i = FirstRow - HasTitle To UBound(copyArr, 1)
            If Not FindText1 Then
'                FindStr1 là dạng ><= xyz vậy đọc giá trị tại dòng hiện hành ở cột ColIndex
                Number = CDbl(copyArr(i, ColIndex))
'                 kiểm tra lỗi vì dữ liệu đầu vào có thể chứa lỗi
                If Err.Number = 0 Then
'                   giá trị đó là số vậy tính kết quả của đk1
                    res = Evaluate(Number & FindStr1)
                Else
'                    nếu dòng không chứa số thì ...
                    Err.Clear
                End If
            Else
                sArr = UCase(copyArr(i, ColIndex))
'                 FinStr1 là dạng văn bản vậy kiểm tra xem ký tự đầu của FindStr1 có phải là "!" hay không, tức xem
'                 FindStr1 có dạng !xyz hay không.
                If Left(FindStr1, 1) = "!" Then
'                     FindStr1 có dạng "!xyz" vậy ta tính kết quả của đk1 - dòng hiện hành ở cột ColIndex không chứa cụm "xyz"
                    res = Not (sArr Like UCase(Mid(FindStr1, 2, Len(FindStr1))))
                Else
'                     FindStr1 không có dạng "!xyz" vậy ta tính kết quả của đk1 -  dòng hiện hành ở cột ColIndex chứa cụm "xyz"
                    res = sArr Like UCase(FindStr1)
                End If
            End If
'            block IF ... END IF chỉ thực hiện khi có mask 2 - FindStr2
            If Not IsMissing(FindStr2) And (FindStr2 <> "") Then
'           ta chỉ xét đk2 khi đk1 thỏa và toán tử là AND hoặc đk1 không thỏa và toán tử là OR
                If Not (res Xor arg_and) Then
                    If Not FindText2 Then
'                        FindStr2 là dạng ><= xyz vậy đọc giá trị tại dòng hiện hành ở cột ColIndex
                        Number = CDbl(copyArr(i, ColIndex))
                        ' kiểm tra lỗi vì dữ liệu đầu vào có thể chứa lỗi
                        If Err.Number = 0 Then
'                            giá trị đó là số vậy tính kết quả của đk1 và đk2
                            If arg_and Then
                                res = res And Evaluate(Number & FindStr2)
                            Else
                                res = res Or Evaluate(Number & FindStr2)
                            End If
                        Else
'                            nếu dòng không chứa số thì ...
                            Err.Clear
                        End If
                    Else
                        sArr = UCase(copyArr(i, ColIndex))
'                        FinStr2 là dạng văn bản vậy kiểm tra xem ký tự đầu của FindStr2 có phải là "!" hay không, tức xem
'                       FindStr2 có dạng !xyz hay không
                        If Left(FindStr2, 1) = "!" Then
'                            FindStr2 có dạng "!xyz" vậy ta tính kết quả của đk2 - dòng hiện hành ở cột ColIndex không chứa cụm "xyz"
                            tmpres = Not (sArr Like UCase(Mid(FindStr2, 2, Len(FindStr2))))
                        Else
'                            FindStr2 không có dạng "!xyz" vậy ta tính kết quả của đk2 -  dòng hiện hành ở cột ColIndex chứa cụm "xyz"
                            tmpres = sArr Like UCase(FindStr2)
                        End If
'                        ta tính kết quả của đk1 và đk2
                        If arg_and Then
                            res = res And tmpres
                        Else
                            res = res Or tmpres
                        End If
                    End If
                End If
            End If
'            nếu đk thỏa thì thêm chỉ số dòng hiện hành vào từ điển
            If res Then Dict.Add i, ""
        Next
'         nếu trong từ điển có dữ liệu là các chỉ số dòng được chọn thì các chỉ số đó là các Key trong mảng Keys
        If Dict.count > 0 Or HasTitle Then
'            mảng chứa các chỉ số các dòng được chọn
            rows_found = Dict.Keys
'             tạo mảng Arr có số dòng bằng số chỉ số dòng được chọn - HasTitle (chỉ số dòng đầu là FirstRow) và số cột bằng
'            số côt của mảng nguồn sArray
            ReDim Arr(FirstRow To UBound(rows_found) + FirstRow - HasTitle, LBound(copyArr, 2) To UBound(copyArr, 2))
'                 ghi các dòng của mảng nguồn mà có chỉ số là các phần tử cua Dict.Keys (tức các dòng được lấy) vào mảng Arr
                For i = FirstRow - HasTitle To UBound(rows_found) + FirstRow - HasTitle
                    currRow = i - FirstRow + HasTitle
                    For j = LBound(copyArr, 2) To UBound(copyArr, 2)
                        Arr(i, j) = copyArr(rows_found(currRow), j)
                    Next
                Next
'             nếu mảng nguồn có chứa tiêu đề thì ghi tiêu đề vào mảng Arr ở dòng đầu tiên
            If HasTitle Then
                For j = LBound(copyArr, 2) To UBound(copyArr, 2)
                    Arr(FirstRow, j) = copyArr(FirstRow, j)
                Next
            End If
        End If
'         trả về mảng các dòng được chọn - lọc
        Filter2DArray = Arr
        
        Set Dict = Nothing
End Function

Mọi thông số đều được ghi chú, code cũng có ghi chú đầy đủ nên chắc không cần giải thích gì thêm. Nên kiểm tra lại vì có thể khi tôi gõ bàn phím có lỗi.
Tôi cũng đính kèm module. Muốn xem được chú thích thì trong VBE: Tools --> Options... --> thẻ Editor Format --> mục Font --> chọn Times New Roman (vietnamese)
------------------
Nếu bạn cứ muốn xem phiên bản dùng RegExp thì ta giao kèo với nhau thế này: tôi đính kèm project, bạn test và thông báo kết quả. Nếu bạn không thông báo kết quả - dù đúng, sai, còn lỗi - thì lần sau có ai đề nghị code tôi sẽ không gửi nữa.
Bất kể ai lập trình dù "ông lớn" hay "nhỏ" cũng rất cần những người test hộ. Những ông lớn họ có cả một đội ngũ tester cơ mà.
 

File đính kèm

Upvote 0
Theo tôi hàm của ndu sửa chút để lọc với 2 đk là thỏa 99,99% nhu cầu rồi. Cũng chả cần thỏa 0,01% kia làm gì. Vì thực ra để dùng cho hết chức năng thì phải biết về RegExp còn không nếu chỉ dùng pattern đơn giản thì dùng luôn LIKE cho rồi.
Nhưng với code hiện thời thì 2 đk vẫn chưa độc lập với nhau với nghĩa là nếu FindStr1 là lọc theo chuỗi (ngày tháng, số - tức ở đầu có ><=) thì code cho là FindStr2 cũng lọc theo chuỗi (ngày tháng, số). Muốn 2 đk hoàn toàn độc lập, tức FindStr1, FindStr2 có thể lọc theo chuỗi, số mà không phụ thuộc vào nhau - vd. FindStr1 lọc theo chuỗi, FindStr2 lọc theo so sánh số thì cũng chỉ cần sửa code chút ít thôi.


Mọi thông số đều được ghi chú, code cũng có ghi chú đầy đủ nên chắc không cần giải thích gì thêm. Nên kiểm tra lại vì có thể khi tôi gõ bàn phím có lỗi.
Tôi cũng đính kèm module. Muốn xem được chú thích thì trong VBE: Tools --> Options... --> thẻ Editor Format --> mục Font --> chọn Times New Roman (vietnamese)
------------------
Nếu bạn cứ muốn xem phiên bản dùng RegExp thì ta giao kèo với nhau thế này: tôi đính kèm project, bạn test và thông báo kết quả. Nếu bạn không thông báo kết quả - dù đúng, sai, còn lỗi - thì lần sau có ai đề nghị code tôi sẽ không gửi nữa.
Bất kể ai lập trình dù "ông lớn" hay "nhỏ" cũng rất cần những người test hộ. Những ông lớn họ có cả một đội ngũ tester cơ mà.

Với cái file Excel, em đã test với thủ tục của nút lệnh như sau:

PHP:
Sub Button1_Click()
Dim Arr, FindStr As String, cot As Long
    
    cot = Range("E17").Value
    FindStr = Selection.Value
    
    Range("F:G").ClearContents
    Arr = Range("A1:B34").Value
    Arr = Filter2DArray(Arr, cot, True, FindStr, True, False)
    Range("F1").Resize(UBound(Arr), 2).Value = Arr
End Sub

Gõ vào ô E17 (1 hoặc 2) tương ứng cột 1, cột 2
Chọn một ô trong cột C và bấm nút.

Kiểm sơ bộ thì Cột 1 dạng ngày tháng thì cho đúng kết quả.

Cột 2 dạng chuỗi thì các ký tự Anh để sẳn không thấy nhúc nhích gì cả!

===================================================
Tới giờ phải về nhà rồi, có gì em sẽ tiếp tục check và báo kết quả Anh sau, tuy nhiên cũng cần có nhiều thời gian mới check hầu hết các trường hợp, nếu có phản hồi chậm cũng là chuyện rất bình thường thôi Anh à.

Trân trọng cám ơn Anh.
 
Lần chỉnh sửa cuối:
Upvote 0
Với cái file Excel, em đã test với thủ tục của nút lệnh như sau:

PHP:
Sub Button1_Click()
Dim Arr, FindStr As String, cot As Long
    
    cot = Range("E17").Value
    FindStr = Selection.Value
    
    Range("F:G").ClearContents
    Arr = Range("A1:B34").Value
    Arr = Filter2DArray(Arr, cot, True, FindStr, True, False)
    Range("F1").Resize(UBound(Arr), 2).Value = Arr
End Sub

Gõ vào ô E17 (1 hoặc 2) tương ứng cột 1, cột 2
Chọn một ô trong cột C và bấm nút.

Kiểm sơ bộ thì Cột 1 dạng ngày tháng thì cho đúng kết quả.

Cột 2 dạng chuỗi thì các ký tự Anh để sẳn không thấy nhúc nhích gì cả!

===================================================
Tới giờ phải về nhà rồi, có gì em sẽ tiếp tục check và báo kết quả Anh sau, tuy nhiên cũng cần có nhiều thời gian mới check hầu hết các trường hợp, nếu có phản hồi chậm cũng là chuyện rất bình thường thôi Anh à.

Trân trọng cám ơn Anh.

Tôi đã ghi chú rất rõ nhưng bạn chắc không đọc:
Có 3 loại MẪU
' 1. loại "><=xyz" - xyz là các chữ số, tức ký tự đầu là >, >=, <, <= hoặc =. Khớp khi dòng ở cột ColIndex có giá trị "abc" mà abc ><= xyz
' 2. loại "!xyz" - Khớp khi dòng ở cột ColIndex không có cụm ký tự "xyz"
' 3. loại "xyz" - Khớp khi dòng ở cột ColIndex có cụm ký tự "xyz"
' FindText1 và FindText2 xác định mẫu là dạng nào. Nếu FindText1 hoặc FindText2 = False thì có nghĩa là FindStr1 hoặc FindStr2
' là mẫu loại 1
-------------------
Nếu bạn gõ vào E17 số 1 thì bạn tìm trong cột 1, tức cột ngày tháng, tức code:
Arr = Filter2DArray(Arr, cot, True, FindStr, True, False)
là đúng vì FindStr là ngày tháng nên FindText1 = FALSE là đúng - so sánh ngày tháng, số
Nhưng nếu bạn nhập vào E17 số 2, tức tìm trong cột 2 là cột họ tên mà vẫn code:
Arr = Filter2DArray(Arr, cot, True, FindStr, True, False)
thì sai là đúng rồi.
Với cột 2 thì là bạn đang tìm "chuỗi" cơ mà? Tức FindStr nó là chuỗi chứ không phải đk so sánh số.
Vì thế với FindStr là tìm "chuỗi" thì đương nhiên phải nhập FindText1 = TRUE.
------------
Code phải là
Mã:
Sub Button1_Click()
Dim Arr, FindStr As String, cot As Long, FindText As Boolean
    
    cot = Range("E17").Value
    FindStr = Selection.Value
    FindText = cot = 2
    
    Range("F:G").ClearContents
    Arr = Range("A1:B34").Value
    Arr = Filter2DArray(Arr, cot, True, FindStr, True, FindText)
    Range("F1").Resize(UBound(Arr), 2).Value = Arr
End Sub

Hoặc:
Mã:
Sub Button1_Click()
Dim Arr, FindStr As String, cot As Long
    
    cot = Range("E17").Value
    FindStr = Selection.Value
    
    Range("F:G").ClearContents
    Arr = Range("A1:B34").Value
    Arr = Filter2DArray(Arr, cot, True, FindStr, True, cot = 2)
    Range("F1").Resize(UBound(Arr), 2).Value = Arr
End Sub
 
Upvote 0
Tôi đã ghi chú rất rõ nhưng bạn chắc không đọc:
Có 3 loại MẪU
' 1. loại "><=xyz" - xyz là các chữ số, tức ký tự đầu là >, >=, <, <= hoặc =. Khớp khi dòng ở cột ColIndex có giá trị "abc" mà abc ><= xyz
' 2. loại "!xyz" - Khớp khi dòng ở cột ColIndex không có cụm ký tự "xyz"
' 3. loại "xyz" - Khớp khi dòng ở cột ColIndex có cụm ký tự "xyz"
' FindText1 và FindText2 xác định mẫu là dạng nào. Nếu FindText1 hoặc FindText2 = False thì có nghĩa là FindStr1 hoặc FindStr2
' là mẫu loại 1
-------------------
Nếu bạn gõ vào E17 số 1 thì bạn tìm trong cột 1, tức cột ngày tháng, tức code:
Arr = Filter2DArray(Arr, cot, True, FindStr, True, False)
là đúng vì FindStr là ngày tháng nên FindText1 = FALSE là đúng - so sánh ngày tháng, số
Nhưng nếu bạn nhập vào E17 số 2, tức tìm trong cột 2 là cột họ tên mà vẫn code:
Arr = Filter2DArray(Arr, cot, True, FindStr, True, False)
thì sai là đúng rồi.
Với cột 2 thì là bạn đang tìm "chuỗi" cơ mà? Tức FindStr nó là chuỗi chứ không phải đk so sánh số.
Vì thế với FindStr là tìm "chuỗi" thì đương nhiên phải nhập FindText1 = TRUE.
------------
Code phải là
Mã:
Sub Button1_Click()
Dim Arr, FindStr As String, cot As Long, FindText As Boolean
    
    cot = Range("E17").Value
    FindStr = Selection.Value
    FindText = cot = 2
    
    Range("F:G").ClearContents
    Arr = Range("A1:B34").Value
    Arr = Filter2DArray(Arr, cot, True, FindStr, True, FindText)
    Range("F1").Resize(UBound(Arr), 2).Value = Arr
End Sub

Hoặc:
Mã:
Sub Button1_Click()
Dim Arr, FindStr As String, cot As Long
    
    cot = Range("E17").Value
    FindStr = Selection.Value
    
    Range("F:G").ClearContents
    Arr = Range("A1:B34").Value
    Arr = Filter2DArray(Arr, cot, True, FindStr, True, cot = 2)
    Range("F1").Resize(UBound(Arr), 2).Value = Arr
End Sub

Vâng, em sẽ "đọc kỹ hướng dẫn sử dụng trước khi dùng" hơn. Cũng gấp gấp muốn về nhưng lại muốn nấn ná ở lại. Giờ quyết tâm đi về nhà hihihi. Mai em cố gắng kiểm tra thêm, giờ mắt đã mõi lắm rồi, đầu óc quay cuồng hết nhập tâm nổi rồi! Cám ơn Anh nhiều!
 
Upvote 0
Cho mình hỏi về ham filter2Darray khi trích lọc dữ liệu có thể lấy k cột cần thiết chứ không phải toàn vùng dữ liệu, ví dụ dữ liệu có 10 cột khi trích lọc minh chỉ cần lấy cột 3,5,8 chẳng hạn thì có đc ko? Nếu có thể thì hướng dẫn cho mình cách lấy. Thanks!
 
Upvote 0
PHP:
Function Filter2DArray(ByVal sArray, ByVal ColIndex As Long, ByVal FindStr As String, ByVal HasTitle As Boolean)
  Dim tmpArr, i As Long, j As Long, Arr, Dic, TmpStr, Tmp, Chk As Boolean, TmpVal As Double
  On Error Resume Next
  Set Dic = CreateObject("Scripting.Dictionary")
  tmpArr = sArray
  ColIndex = ColIndex + LBound(tmpArr, 2) - 1
  Chk = (InStr("><=", Left(FindStr, 1)) > 0)
  For i = LBound(tmpArr, 1) - HasTitle To UBound(tmpArr, 1)
    If Chk Then
      TmpVal = CDbl(tmpArr(i, ColIndex))
      If Evaluate(TmpVal & FindStr) Then Dic.Add i, ""
    Else
      If UCase(tmpArr(i, ColIndex)) Like UCase(FindStr) Then Dic.Add i, ""
    End If
  Next
  If Dic.Count > 0 Then
    Tmp = Dic.Keys
    ReDim Arr(LBound(tmpArr, 1) To UBound(Tmp) + LBound(tmpArr, 1) - HasTitle, LBound(tmpArr, 2) To UBound(tmpArr, 2))
    For i = LBound(tmpArr, 1) - HasTitle To UBound(Tmp) + LBound(tmpArr, 1) - HasTitle
      For j = LBound(tmpArr, 2) To UBound(tmpArr, 2)
        Arr(i, j) = tmpArr(Tmp(i - LBound(tmpArr, 1) + HasTitle), j)
      Next
    Next
    If HasTitle Then
      For j = LBound(tmpArr, 2) To UBound(tmpArr, 2)
        Arr(LBound(tmpArr, 1), j) = tmpArr(LBound(tmpArr, 1), j)
      Next
    End If
  End If
  Filter2DArray = Arr
End Function

Cho em hỏi
Form có 2 textbox (txtBatDau, txtKetThuc) và 1 nút lệnh

[GPECODE=vba]Private Sub CommandButton1_Click()
Dim Arr
LstDLNgay.Clear
Arr = Filter2DArray(sArray, 2, txtBatDau.Text & "*", False)
Arr = Filter2DArray(Arr, 1, txtKetThuc.Text & "*", False)
If IsArray(Arr) Then LstDLNgay.List() = Arr
End Sub
[/GPECODE]
File https://drive.google.com/file/d/0Bz23-2tBuYb1U21wWkVGRjFmUms/view?usp=sharing
Vậy làm như thế nào để lọc kết quả trong khoảng ngày được chọn ở txtBatDau, txtKetThuc
Trân trọng!
 
Lần chỉnh sửa cuối:
Upvote 0
Cho em hỏi
Form có 2 textbox (txtBatDau, txtKetThuc) và 1 nút lệnh

[GPECODE=vba]Private Sub CommandButton1_Click()
Dim Arr
LstDLNgay.Clear
Arr = Filter2DArray(sArray, 2, txtBatDau.Text & "*", False)
Arr = Filter2DArray(Arr, 1, txtKetThuc.Text & "*", False)
If IsArray(Arr) Then LstDLNgay.List() = Arr
End Sub
[/GPECODE]
File https://drive.google.com/file/d/0Bz23-2tBuYb1U21wWkVGRjFmUms/view?usp=sharing
Vậy làm như thế nào để lọc kết quả trong khoảng ngày được chọn ở txtBatDau, txtKetThuc
Trân trọng!

Tôi đang sử dụng điện thoại nên không biết phải làm sao, nhưng bạn thử xem qua bài viết này để ứng dụng cho yêu cầu của bạn.

http://www.giaiphapexcel.com/forum/...er-dành-cho-mảng-2-chiều)&p=715728#post715728
 
Lần chỉnh sửa cuối:
Upvote 0
Upvote 0
Tôi đang sử dụng điện thoại nên không biết phải làm sao, nhưng bạn thử xem qua bài viết này để ứng dụng cho yêu cầu của bạn.

http://www.giaiphapexcel.com/forum/...er-dành-cho-mảng-2-chiều)&p=715728#post715728

Anh cho em hỏi khi em test với 2 điều kiện
PHP:
Arr = SimpleFilter(Range("a4:c33").Value, 3, ">", "23/04/2016  07:20", "d", "1,3,2", xlAnd, 2, "=", "*1", "s")
thì xuất hiện lỗi ở đoạn

[GPECODE=vba]If xlOperator = xlAnd Then
For r = lbd1 To ubd1
If LCase(sArray2D(r, lngField2)) Like Criteria2 _
And Evaluate(CDbl(sArray2D(r, lngField1)) & strCompareMark1 & Criteria1) Then
n = n + 1
ReDim Preserve GetRow(1 To n)
GetRow(n) = r
End If
Next
Else
For r = lbd1 To ubd1
If LCase(sArray2D(r, lngField2)) Like Criteria2 _
Or Evaluate(CDbl(sArray2D(r, lngField1)) & strCompareMark1 & Criteria1) Then
n = n + 1
ReDim Preserve GetRow(1 To n)
GetRow(n) = r
End If
Next
End If
[/GPECODE]

P/s: Mà hình như lọc theo kiểu dạng "d" là bị lỗi hết à anh
 
Lần chỉnh sửa cuối:
Upvote 0
Anh cho em hỏi khi em test với 2 điều kiện
PHP:
Arr = SimpleFilter(Range("a4:c33").Value, 3, ">", "23/04/2016  07:20", "d", "1,3,2", xlAnd, 2, "=", "*1", "s")
thì xuất hiện lỗi ở đoạn

[GPECODE=vba]If xlOperator = xlAnd Then
For r = lbd1 To ubd1
If LCase(sArray2D(r, lngField2)) Like Criteria2 _
And Evaluate(CDbl(sArray2D(r, lngField1)) & strCompareMark1 & Criteria1) Then
n = n + 1
ReDim Preserve GetRow(1 To n)
GetRow(n) = r
End If
Next
Else
For r = lbd1 To ubd1
If LCase(sArray2D(r, lngField2)) Like Criteria2 _
Or Evaluate(CDbl(sArray2D(r, lngField1)) & strCompareMark1 & Criteria1) Then
n = n + 1
ReDim Preserve GetRow(1 To n)
GetRow(n) = r
End If
Next
End If
[/GPECODE]

P/s: Mà hình như lọc theo kiểu dạng "d" là bị lỗi hết à anh

Bạn test trên textbox hay trên sheet? Bởi nếu trên textbox thì không phải dạng ngày tháng nhé!
Nếu điều kiện trên textbox sẽ: CDbl(textbox) còn chuỗi "31/12/2016" thì: CDbl("31/12/2016")
 
Lần chỉnh sửa cuối:
Upvote 0
Bạn test trên textbox hay trên sheet? Bởi nếu trên textbox thì không phải dạng ngày tháng nhé!
Nếu điều kiện trên textbox sẽ: CDbl(textbox) còn chuỗi "31/12/2016" thì: CDbl("31/12/2016")
Dạ, em tải file anh về và test trên Sheet à anh. (Em chưa có thử đưa lên Form)
 
Upvote 0
Tôi có thêm ở bài #54 hàm CDbl, bạn có đọc qua chưa?

Em có đọc qua rồi, nhưng chưa có test thử xem ( do đang sử dụng điện thoại)

P/s: Em đưa vô form rồi, nhưng không được. Nhờ các anh chị giúp em
https://drive.google.com/file/d/0Bz23-2tBuYb1U21wWkVGRjFmUms/view?usp=sharing
Thực tế khi test trên sheet nếu Decimal Symbol là dấu "," và Digil ... là dấu "." thì lọc theo dạng "d" bị lỗi. Phải đổi ngược lại dấu Decimal Symbol là dấu "." và Digil ... là dấu "," thì Ok.
Có cách nào mình khắc phục tình trạng không phân biệt dấu của Decimal Symbol và Digil (dấu nào cũng lọc được) .. được không anh
Còn trường hợp trên Form nhờ anh giúp đỡ
 
Lần chỉnh sửa cuối:
Upvote 0
Em có đọc qua rồi, nhưng chưa có test thử xem ( do đang sử dụng điện thoại)

P/s: Em đưa vô form rồi, nhưng không được. Nhờ các anh chị giúp em
https://drive.google.com/file/d/0Bz23-2tBuYb1U21wWkVGRjFmUms/view?usp=sharing
Thực tế khi test trên sheet nếu Decimal Symbol là dấu "," và Digil ... là dấu "." thì lọc theo dạng "d" bị lỗi. Phải đổi ngược lại dấu Decimal Symbol là dấu "." và Digil ... là dấu "," thì Ok.
Có cách nào mình khắc phục tình trạng không phân biệt dấu của Decimal Symbol và Digil (dấu nào cũng lọc được) .. được không anh
Còn trường hợp trên Form nhờ anh giúp đỡ

Tôi bó tay với việc ứng dụng của bạn luôn đó:

Code của bạn:

Mã:
Sub Test()
    Dim Arr
    LstDLNgay.Clear
[COLOR=#b22222]    Arr = Sheet1.Range(Sheet1.[A2], Sheet1.[D1000].End(xlUp)).Value[/COLOR]
    Arr = SimpleFilter([COLOR=#b22222]Range("a2:d1000").Value[/COLOR], [B][SIZE=4][COLOR=#ff0000]3[/COLOR][/SIZE][/B], ">=", CDbl(txtBatDau), "d", [COLOR=#0000ff][B]"1,2,3,4"[/B][/COLOR], xlAnd, [B][SIZE=4][COLOR=#FF0000]3[/COLOR][/SIZE][/B], "<=", CDbl(txtKetThuc), "d")
    LstDLNgay.List() = Arr
End Sub

Trước mắt bạn đã không hiểu cái hàm nó nói gì rồi! Cột 1 mới chứa ngày tháng, bạn lại đi lọc cột 3 là sao?

Cái thứ 2, những chỗ tôi tô đỏ sậm, tôi không biết bạn ứng dụng cho cái gì.

Chỉ cần như thế này là đủ bạn nhé!

Mã:
Sub Test()
    LstDLNgay.List() = SimpleFilter(sArray, 1, ">=", CDate(txtBatDau), "d", , xlAnd, 1, "<=", CDate(txtKetThuc), "d")
End Sub

Nhưng ở bài trước tôi cũng có một điểm chưa chính xác, đó là, thay vì chỉ bạn dùng CDate, tôi lại hướng dẫn bạn dùng CDbl, nên nó phát sinh ra lỗi không đúng kiểu dữ liệu, nay tôi check trên máy tính nên thấy lỗi này.
 
Lần chỉnh sửa cuối:
Upvote 0
Mà cũng không cần CDate làm gì vì điều kiện trong hàm đã được xử lý việc dùng CDate rồi.

Vậy nên bạn cũng không cần Sub Test nữa, làm luôn trong sự kiện click của nút lệnh:

Mã:
Private Sub CommandButton1_Click()
    LstDLNgay.List() = SimpleFilter(sArray, 1, ">=", txtBatDau, "d", , xlAnd, 1, "<=", txtKetThuc, "d")
End Sub

Vấn đề của bạn là phải lọc đúng cột!
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Mà cũng không cần CDate làm gì vì điều kiện trong hàm đã được xử lý việc dùng CDate rồi.

Vậy nên bạn cũng không cần Sub Test nữa, làm luôn trong sự kiện click của nút lệnh:

Mã:
Private Sub CommandButton1_Click()
    LstDLNgay.List() = SimpleFilter(sArray, 1, ">=", txtBatDau, "d", , xlAnd, 1, "<=", txtKetThuc, "d")
End Sub

Vấn đề của bạn là phải lọc đúng cột!
Cám ơn anh đã giúp đỡ, ngày mai vào cơ quan em sẽ xem kỹ hơn. Có gì nhờ anh hỗ trợ tiếp
Trân trọng cảm ơn anh
 
Upvote 0

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

Back
Top Bottom