Thắc mắc,góp ý hoàn thiện về hàm UDF Filter2DArray (3 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,720
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:
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
Web KT

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

Back
Top Bottom