Trong chủ đề
http://www.giaiphapexcel.com/forum/...LỌC-2-CỘT-tốc-độ-cao-và-cấu-trúc-hàm-đơn-giản!
Hoàng Trọng Nghĩa có so sánh 3 hàm lọc. Tôi nhìn thấy chủ đề này từ lâu nhưng không nghĩ trong "ruột" lại đề cập tới hàm Filter2DArray vì chủ đề nói về AutoFilter.
Hôm nay do rỗi hơi nên tò mò vào xem thì thấy được 3 hàm lọc mà một hàm được gán cho là của siwtom. Tôi xin giải thích như sau.
a. Thực ra hàm Filter2DArray có 2 đk lọc là tôi "cải tiến" từ hàm của ndu để thêm đk thứ hai. Cải tiến nhưng vẫn giữ 90% ý tưởng và cách viết code của Tuấn. Vậy khó có thể gọi là hàm của siwtom.
b. Nếu tôi đập đi xây mới, làm lại từ đầu với ý tưởng khác đi, chọn cách code khác đi thì lúc đó có thể gọi là hàm của siwtom.
c. Khi cải tiến hàm của ndu tôi cũng nhận thấy Evaluate không hay lắm. Đúng là khi ta có 1 biểu thức phức tạp thì bắt buộc ta phải dùng Evaluate vì lúc đó cái quan trọng không phải là tốc độ mà chỉ là khả năng để tính toán được. Nhưng khi xét các biểu thức đơn giản kiểu a > b, A <= b, A <> b thì hoàn toàn có khả năng tính được mà không cần Evaluate.
d. Ngoài Evaluate làm chậm code thì dùng Dictionary cũng làm chậm code. Dictionary mạnh khi lọc duy nhất nhưng khi chỉ cần nhớ các giá trị "chắc chắn" là duy nhất, vd. các chỉ số dòng của mảng, thì dùng Dic.Add làm chậm code. Các bạn có thể kiểm nghiệm điều này bằng cách trong code của tôi dưới đây thay
bằng Dic.Add i, ""
Tuy biết được các điều trên nhưng theo dõi chủ đề "ấy" (nơi tôi cải tiến code của ndu) thì thấy hầu như không ai có nhu cầu nên thôi. Chả ai bỏ công ra làm cái mà người khác không cần.
Nhưng bây giờ thấy Hoàng Trọng Nghĩa có thời gian và kiên nhẫn nên tôi cũng góp vui một code. Nhờ Nghĩa test hộ.
Hàm cho phép lọc số cột tùy ý. Trong mỗi cột có thể có đk lọc chuỗi hoặc số. Nếu là số thì có thể có 2 đk cho cùng 1 cột được kết hợp với nhau bởi AND hoặc OR. Các đk của các cột được kết hợp bởi AND (a and b and c ... and z) hoặc OR (a or b or c ... or z)
Vd. có thể lọc theo 3 cột 1, 2 và 3 - tức các cột Họ Tên, Thời gian, Sản phẩm. Ví dụ ta phải tìm các dòng có Họ tên là "abc", thời gian là từ ... đến ..., và sản phẩm là >= 100. Chú ý là cột Thời gian có 2 đk con được kết hợp bởi AND. Và 3 đk của 3 cột được kết hợp với nhau bởi AND.
vd. sử dụng hàm
--------------------
Hướng dẫn
1. sArray là mảng - range chứa các giá trtị cần lọc.
2. ArrCrit() là mảng 2 chiều có 2 dòng và k cột với k là số cột cần lọc. Dòng đầu chứa lần lượt chỉ số các cột cần lọc - tính từ 1. Dòng 2 chứa các điều kiện lọc cho từng cột.
Nếu điều kiện không bắt đầu bằng ký tự "<", ">" hay "=" thì có nghĩa là lọc chuỗi trong cột.
Nếu điều kiện bắt đầu bằng ký tự "!" thì có nghĩa là loại các giá trị khớp với chuỗi có được từ điều kiện sau khi bỏ ký tự "!".
Nếu điều kiện không bắt đầu bằng ký tự "!" thì có nghĩa là lấy các giá trị khớp với điều kiện.
Nếu điều kiện bắt đầu bằng ký tự "<", ">" hay "=" thì có nghĩa là điều kiện so sánh số. Trong trường hợp này có thể có 1 hoặc 2 điều kiện con. Mỗi điều kiện con phải bắt đầu bằng "<", ">" hoac "=". Nếu có 2 điều kiện con thì phải được kết hợp với nhau bằng ký tự "||" - tức AND - hoặc "|" - tức OR. Ví dụ:
điều kiện ">=150" - tức các giá trị >= 150 sẽ thỏa
điều kiện ">=150||<=200" - tức các giá trị trong khoảng [150;200] sẽ thỏa
điều kiện ">=200|<=150" - tức các giá trị <= 150 hoặc >= 200 sẽ thỏa
3. arg_and xác định cách kết hợp điều kiện của các cột. Nếu arg_and = TRUE thì điều kiện của các cột được kết hợp với nhau bởi toán tử AND, tức các điều kiện đều phải thỏa. Ngược lại thì các điều kiện được kết hợp với nhau bằng toán tử OR
----------------
Code:
[GPECODE=vb]
Option Compare Text
Private Function GoodItem(ByVal item As Double, ByVal value As Double, ByVal ArgumenValue As Long) As Boolean
Select Case ArgumenValue
Case 0: GoodItem = item <> value
Case 1: GoodItem = item <= value
Case 2: GoodItem = item >= value
Case 3: GoodItem = item = value
Case 4: GoodItem = item < value
Case 5: GoodItem = item > value
End Select
End Function
Private Function ArgumenValue(ByVal strArg As String) As Long
Dim kytu As String, Tmp As String
ArgumenValue = -1
kytu = Left(strArg, 1)
If InStr(1, "><=", kytu) <= 0 Then Exit Function
Tmp = Left(strArg, 2)
Select Case Tmp
Case "<>": ArgumenValue = 0
Case "<=": ArgumenValue = 1
Case ">=": ArgumenValue = 2
Case Else
Select Case kytu
Case "=": ArgumenValue = 3
Case "<": ArgumenValue = 4
Case ">": ArgumenValue = 5
End Select
End Select
End Function
Private Sub PrepareArg(ArrCrit(), VarCrit())
Dim col As Long, k As Long, opt As Long, argValue As Long, argValue2 As Long
Dim strCrit, strCrit2, kytu As String
ReDim VarCrit(0 To 5, LBound(ArrCrit, 2) To UBound(ArrCrit, 2))
For col = LBound(VarCrit, 2) To UBound(VarCrit, 2)
strCrit = ArrCrit(UBound(ArrCrit), col)
kytu = Left(strCrit, 1)
If InStr(1, "><=", kytu) > 0 Then
' dieu kien ve so
k = InStr(1, strCrit, "||")
If k > 0 Then
' dieu kien ve so, 2 dk ket hop boi AND
opt = 1
strCrit2 = Mid(strCrit, k + 2)
strCrit = Left(strCrit, k - 1)
Else
k = InStr(1, strCrit, "|")
If k > 0 Then
' dieu kien ve so, 2 dk ket hop boi OR
opt = 2
strCrit2 = Mid(strCrit, k + 1)
strCrit = Left(strCrit, k - 1)
Else
' dieu kien ve so, 1 dk
opt = 0
End If
End If
argValue = ArgumenValue(strCrit)
If argValue > 2 Then
strCrit = Mid(strCrit, 2)
Else
strCrit = Mid(strCrit, 3)
End If
argValue2 = ArgumenValue(strCrit2)
If argValue2 > 2 Then
strCrit2 = Mid(strCrit2, 2)
Else
strCrit2 = Mid(strCrit2, 3)
End If
Else
' dieu kien ve chuoi
If kytu = "!" Then
' dieu kien ve chuoi, phu nhan
opt = 4
strCrit = Mid(strCrit, 2)
Else
' dieu kien ve so, chap nhan
opt = 3
End If
End If
VarCrit(0, col) = ArrCrit(LBound(ArrCrit), col)
VarCrit(1, col) = opt
VarCrit(2, col) = strCrit
VarCrit(3, col) = strCrit2
VarCrit(4, col) = argValue
VarCrit(5, col) = argValue2
Next col
End Sub
Function MyFilter2DArray(ByVal sArray As Variant, ArrCrit(), ByVal HasTitle As Boolean, Optional ByVal arg_and As Boolean = True)
' sArray là mảng - range chứa các giá trị cần lọc
' ArrCrit() la mang 2 chieu co 2 dong va k cot voi k la so cot can loc. Dong dau chua lan luot chi so cac cot can loc - tinh tu 1.
' Dong 2 chua cac dieu kien loc cho tung cot. Neu dieu kien khong bat dau bang ky tu "<", ">" hay "=" thi co nghia la loc chuoi trong cot.
' Neu dieu kien bat dau bang ky tu "!" thi co nghia la loai cac gia tri khop voi chuoi co duoc tu dieu kien sau khi bo ky tu "!". Neu chuoi
' khong bat dau bang ky tu "!" thi co nghia la tim cac gia tri khop voi dieu kien
' Neu dieu kien bat dau bang ky tu "<", ">" hoac "=" thi co nghia la dieu kien la so sanh so. Trong truong hop nay co the co 1 hoac 2
' dieu kien con. Moi dieu kien con phai bat dau bang "<", ">" hoac "=". Neu co 2 dieu kien con thi phai duoc ket hop voi nhau bang
' ky tu "||" - tuc AND - hoac "|" - tuc OR. Vi du:
' dieu kien ">=150" - tuc cac gia tri >= 150 se thoa
' dieu kien ">=150||<=200" - tuc cac gia tri trong khoang [150;200] se thoa
' dieu kien ">=200|<=150" - tuc cac gia tri <= 150 hoac >= 200 se thoa
' arg_and xac dinh cach ket hop dieu kien cua cac cot. Neu arg_and TRUE thi dieu kien cua cac cot duoc ket hop voi nhau boi
' toan tu AND, tuc cac dieu kien deu phai thoa. Nguoc lai thi cac dieu kien duoc ket hop voi nhau boi toan tu OR
' 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, Tmp(), TmpVal As Double, sArr As String, res As Boolean
Dim col As Long, strCrit As String, strCrit2 As String
Dim k As Long, VarCrit(), opt As Long, colIndex As Long
Dim LBoundTmpArr As Long, UBoundTmpArr As Long, LBoundTmpArr2 As Long, UBoundTmpArr2 As Long
Dim LBoundVarCrit2 As Long, UBoundVarCrit2 As Long, TmpcurrRow As Long, count As Long, t As Double
On Error Resume Next
' sao dữ liệu từ sArray sang TmpArr
TmpArr = sArray
If Not IsArray(TmpArr) Then Exit Function
' chuan bi argument
PrepareArg ArrCrit, VarCrit
LBoundTmpArr = LBound(TmpArr, 1)
UBoundTmpArr = UBound(TmpArr, 1)
LBoundTmpArr2 = LBound(TmpArr, 2)
UBoundTmpArr2 = UBound(TmpArr, 2)
LBoundVarCrit2 = LBound(VarCrit, 2)
UBoundVarCrit2 = UBound(VarCrit, 2)
' đi từng dòng trong cột lọc ColIndex và lọc lấy dữ liệu
For i = 1 - HasTitle To UBoundTmpArr
For col = LBoundVarCrit2 To UBoundVarCrit2
opt = VarCrit(1, col)
If opt < 3 Then
' dieu kien ve so
TmpVal = CDbl(TmpArr(i, VarCrit(0, col)))
If Err.Number = 0 Then
res = GoodItem(TmpVal, VarCrit(2, col), VarCrit(4, col))
If (res And opt = 1) Or (Not res And opt = 2) Then res = GoodItem(TmpVal, VarCrit(3, col), VarCrit(5, col))
Else
Err.Clear
res = False
Exit For
End If
Else
' dieu kien ve chuoi
sArr = TmpArr(i, VarCrit(0, col))
If opt = 3 Then
' chap nhan
res = sArr Like VarCrit(2, col)
Else
' phu nhan
res = Not (sArr Like VarCrit(2, col))
End If
End If
If res = Not arg_and Then Exit For
Next col
If res Then
ReDim Preserve Tmp(0 To count)
Tmp(count) = i
count = count + 1
End If
Next i
' nếu trong mang tmp có dữ liệu là các chỉ số dòng được chọn thì ...
If count > 0 Then
' 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(LBoundTmpArr To UBound(Tmp) + LBoundTmpArr - HasTitle, 1 To UBoundTmpArr2)
' ghi các dòng của mảng nguồn mà có chỉ số là các phần tử cua tmp (tức các dòng được lấy) vào mảng Arr
For i = LBoundTmpArr - HasTitle To UBound(Tmp) + LBoundTmpArr - HasTitle
TmpcurrRow = Tmp(i - LBoundTmpArr + HasTitle)
For j = 1 To UBoundTmpArr2
Arr(i, j) = TmpArr(TmpcurrRow, 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 = 1 To UBoundTmpArr2
Arr(LBoundTmpArr, j) = TmpArr(LBoundTmpArr, j)
Next
End If
End If
' trả về mảng các dòng được chọn - lọc
MyFilter2DArray = Arr
End Function
[/GPECODE]
http://www.giaiphapexcel.com/forum/...LỌC-2-CỘT-tốc-độ-cao-và-cấu-trúc-hàm-đơn-giản!
Hoàng Trọng Nghĩa có so sánh 3 hàm lọc. Tôi nhìn thấy chủ đề này từ lâu nhưng không nghĩ trong "ruột" lại đề cập tới hàm Filter2DArray vì chủ đề nói về AutoFilter.
Hôm nay do rỗi hơi nên tò mò vào xem thì thấy được 3 hàm lọc mà một hàm được gán cho là của siwtom. Tôi xin giải thích như sau.
a. Thực ra hàm Filter2DArray có 2 đk lọc là tôi "cải tiến" từ hàm của ndu để thêm đk thứ hai. Cải tiến nhưng vẫn giữ 90% ý tưởng và cách viết code của Tuấn. Vậy khó có thể gọi là hàm của siwtom.
b. Nếu tôi đập đi xây mới, làm lại từ đầu với ý tưởng khác đi, chọn cách code khác đi thì lúc đó có thể gọi là hàm của siwtom.
c. Khi cải tiến hàm của ndu tôi cũng nhận thấy Evaluate không hay lắm. Đúng là khi ta có 1 biểu thức phức tạp thì bắt buộc ta phải dùng Evaluate vì lúc đó cái quan trọng không phải là tốc độ mà chỉ là khả năng để tính toán được. Nhưng khi xét các biểu thức đơn giản kiểu a > b, A <= b, A <> b thì hoàn toàn có khả năng tính được mà không cần Evaluate.
d. Ngoài Evaluate làm chậm code thì dùng Dictionary cũng làm chậm code. Dictionary mạnh khi lọc duy nhất nhưng khi chỉ cần nhớ các giá trị "chắc chắn" là duy nhất, vd. các chỉ số dòng của mảng, thì dùng Dic.Add làm chậm code. Các bạn có thể kiểm nghiệm điều này bằng cách trong code của tôi dưới đây thay
Mã:
ReDim Preserve Tmp(0 To count)
Tmp(count) = i
count = count + 1
bằng Dic.Add i, ""
Tuy biết được các điều trên nhưng theo dõi chủ đề "ấy" (nơi tôi cải tiến code của ndu) thì thấy hầu như không ai có nhu cầu nên thôi. Chả ai bỏ công ra làm cái mà người khác không cần.
Nhưng bây giờ thấy Hoàng Trọng Nghĩa có thời gian và kiên nhẫn nên tôi cũng góp vui một code. Nhờ Nghĩa test hộ.
Hàm cho phép lọc số cột tùy ý. Trong mỗi cột có thể có đk lọc chuỗi hoặc số. Nếu là số thì có thể có 2 đk cho cùng 1 cột được kết hợp với nhau bởi AND hoặc OR. Các đk của các cột được kết hợp bởi AND (a and b and c ... and z) hoặc OR (a or b or c ... or z)
Vd. có thể lọc theo 3 cột 1, 2 và 3 - tức các cột Họ Tên, Thời gian, Sản phẩm. Ví dụ ta phải tìm các dòng có Họ tên là "abc", thời gian là từ ... đến ..., và sản phẩm là >= 100. Chú ý là cột Thời gian có 2 đk con được kết hợp bởi AND. Và 3 đk của 3 cột được kết hợp với nhau bởi AND.
vd. sử dụng hàm
Mã:
Dim sArray, ArrCrit(1 To 2, 1 To 2)
ArrCrit(1, 1) = 4
ArrCrit(2, 1) = ">=10||<=100"
ArrCrit(1, 2) = 6
ArrCrit(2, 2) = ">=" & CDbl(DateSerial(2011, 11, 24))
sArray = MyFilter2DArray([A34:F65536], ArrCrit, False)
Mã:
Dim sArray, ArrCrit(1 To 2, 1 To 1)
ArrCrit(1, 1) = 4
ArrCrit(2, 1) = ">500"
sArray = MyFilter2DArray([A2:F65536], ArrCrit, True)
Hướng dẫn
1. sArray là mảng - range chứa các giá trtị cần lọc.
2. ArrCrit() là mảng 2 chiều có 2 dòng và k cột với k là số cột cần lọc. Dòng đầu chứa lần lượt chỉ số các cột cần lọc - tính từ 1. Dòng 2 chứa các điều kiện lọc cho từng cột.
Nếu điều kiện không bắt đầu bằng ký tự "<", ">" hay "=" thì có nghĩa là lọc chuỗi trong cột.
Nếu điều kiện bắt đầu bằng ký tự "!" thì có nghĩa là loại các giá trị khớp với chuỗi có được từ điều kiện sau khi bỏ ký tự "!".
Nếu điều kiện không bắt đầu bằng ký tự "!" thì có nghĩa là lấy các giá trị khớp với điều kiện.
Nếu điều kiện bắt đầu bằng ký tự "<", ">" hay "=" thì có nghĩa là điều kiện so sánh số. Trong trường hợp này có thể có 1 hoặc 2 điều kiện con. Mỗi điều kiện con phải bắt đầu bằng "<", ">" hoac "=". Nếu có 2 điều kiện con thì phải được kết hợp với nhau bằng ký tự "||" - tức AND - hoặc "|" - tức OR. Ví dụ:
điều kiện ">=150" - tức các giá trị >= 150 sẽ thỏa
điều kiện ">=150||<=200" - tức các giá trị trong khoảng [150;200] sẽ thỏa
điều kiện ">=200|<=150" - tức các giá trị <= 150 hoặc >= 200 sẽ thỏa
3. arg_and xác định cách kết hợp điều kiện của các cột. Nếu arg_and = TRUE thì điều kiện của các cột được kết hợp với nhau bởi toán tử AND, tức các điều kiện đều phải thỏa. Ngược lại thì các điều kiện được kết hợp với nhau bằng toán tử OR
----------------
Code:
[GPECODE=vb]
Option Compare Text
Private Function GoodItem(ByVal item As Double, ByVal value As Double, ByVal ArgumenValue As Long) As Boolean
Select Case ArgumenValue
Case 0: GoodItem = item <> value
Case 1: GoodItem = item <= value
Case 2: GoodItem = item >= value
Case 3: GoodItem = item = value
Case 4: GoodItem = item < value
Case 5: GoodItem = item > value
End Select
End Function
Private Function ArgumenValue(ByVal strArg As String) As Long
Dim kytu As String, Tmp As String
ArgumenValue = -1
kytu = Left(strArg, 1)
If InStr(1, "><=", kytu) <= 0 Then Exit Function
Tmp = Left(strArg, 2)
Select Case Tmp
Case "<>": ArgumenValue = 0
Case "<=": ArgumenValue = 1
Case ">=": ArgumenValue = 2
Case Else
Select Case kytu
Case "=": ArgumenValue = 3
Case "<": ArgumenValue = 4
Case ">": ArgumenValue = 5
End Select
End Select
End Function
Private Sub PrepareArg(ArrCrit(), VarCrit())
Dim col As Long, k As Long, opt As Long, argValue As Long, argValue2 As Long
Dim strCrit, strCrit2, kytu As String
ReDim VarCrit(0 To 5, LBound(ArrCrit, 2) To UBound(ArrCrit, 2))
For col = LBound(VarCrit, 2) To UBound(VarCrit, 2)
strCrit = ArrCrit(UBound(ArrCrit), col)
kytu = Left(strCrit, 1)
If InStr(1, "><=", kytu) > 0 Then
' dieu kien ve so
k = InStr(1, strCrit, "||")
If k > 0 Then
' dieu kien ve so, 2 dk ket hop boi AND
opt = 1
strCrit2 = Mid(strCrit, k + 2)
strCrit = Left(strCrit, k - 1)
Else
k = InStr(1, strCrit, "|")
If k > 0 Then
' dieu kien ve so, 2 dk ket hop boi OR
opt = 2
strCrit2 = Mid(strCrit, k + 1)
strCrit = Left(strCrit, k - 1)
Else
' dieu kien ve so, 1 dk
opt = 0
End If
End If
argValue = ArgumenValue(strCrit)
If argValue > 2 Then
strCrit = Mid(strCrit, 2)
Else
strCrit = Mid(strCrit, 3)
End If
argValue2 = ArgumenValue(strCrit2)
If argValue2 > 2 Then
strCrit2 = Mid(strCrit2, 2)
Else
strCrit2 = Mid(strCrit2, 3)
End If
Else
' dieu kien ve chuoi
If kytu = "!" Then
' dieu kien ve chuoi, phu nhan
opt = 4
strCrit = Mid(strCrit, 2)
Else
' dieu kien ve so, chap nhan
opt = 3
End If
End If
VarCrit(0, col) = ArrCrit(LBound(ArrCrit), col)
VarCrit(1, col) = opt
VarCrit(2, col) = strCrit
VarCrit(3, col) = strCrit2
VarCrit(4, col) = argValue
VarCrit(5, col) = argValue2
Next col
End Sub
Function MyFilter2DArray(ByVal sArray As Variant, ArrCrit(), ByVal HasTitle As Boolean, Optional ByVal arg_and As Boolean = True)
' sArray là mảng - range chứa các giá trị cần lọc
' ArrCrit() la mang 2 chieu co 2 dong va k cot voi k la so cot can loc. Dong dau chua lan luot chi so cac cot can loc - tinh tu 1.
' Dong 2 chua cac dieu kien loc cho tung cot. Neu dieu kien khong bat dau bang ky tu "<", ">" hay "=" thi co nghia la loc chuoi trong cot.
' Neu dieu kien bat dau bang ky tu "!" thi co nghia la loai cac gia tri khop voi chuoi co duoc tu dieu kien sau khi bo ky tu "!". Neu chuoi
' khong bat dau bang ky tu "!" thi co nghia la tim cac gia tri khop voi dieu kien
' Neu dieu kien bat dau bang ky tu "<", ">" hoac "=" thi co nghia la dieu kien la so sanh so. Trong truong hop nay co the co 1 hoac 2
' dieu kien con. Moi dieu kien con phai bat dau bang "<", ">" hoac "=". Neu co 2 dieu kien con thi phai duoc ket hop voi nhau bang
' ky tu "||" - tuc AND - hoac "|" - tuc OR. Vi du:
' dieu kien ">=150" - tuc cac gia tri >= 150 se thoa
' dieu kien ">=150||<=200" - tuc cac gia tri trong khoang [150;200] se thoa
' dieu kien ">=200|<=150" - tuc cac gia tri <= 150 hoac >= 200 se thoa
' arg_and xac dinh cach ket hop dieu kien cua cac cot. Neu arg_and TRUE thi dieu kien cua cac cot duoc ket hop voi nhau boi
' toan tu AND, tuc cac dieu kien deu phai thoa. Nguoc lai thi cac dieu kien duoc ket hop voi nhau boi toan tu OR
' 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, Tmp(), TmpVal As Double, sArr As String, res As Boolean
Dim col As Long, strCrit As String, strCrit2 As String
Dim k As Long, VarCrit(), opt As Long, colIndex As Long
Dim LBoundTmpArr As Long, UBoundTmpArr As Long, LBoundTmpArr2 As Long, UBoundTmpArr2 As Long
Dim LBoundVarCrit2 As Long, UBoundVarCrit2 As Long, TmpcurrRow As Long, count As Long, t As Double
On Error Resume Next
' sao dữ liệu từ sArray sang TmpArr
TmpArr = sArray
If Not IsArray(TmpArr) Then Exit Function
' chuan bi argument
PrepareArg ArrCrit, VarCrit
LBoundTmpArr = LBound(TmpArr, 1)
UBoundTmpArr = UBound(TmpArr, 1)
LBoundTmpArr2 = LBound(TmpArr, 2)
UBoundTmpArr2 = UBound(TmpArr, 2)
LBoundVarCrit2 = LBound(VarCrit, 2)
UBoundVarCrit2 = UBound(VarCrit, 2)
' đi từng dòng trong cột lọc ColIndex và lọc lấy dữ liệu
For i = 1 - HasTitle To UBoundTmpArr
For col = LBoundVarCrit2 To UBoundVarCrit2
opt = VarCrit(1, col)
If opt < 3 Then
' dieu kien ve so
TmpVal = CDbl(TmpArr(i, VarCrit(0, col)))
If Err.Number = 0 Then
res = GoodItem(TmpVal, VarCrit(2, col), VarCrit(4, col))
If (res And opt = 1) Or (Not res And opt = 2) Then res = GoodItem(TmpVal, VarCrit(3, col), VarCrit(5, col))
Else
Err.Clear
res = False
Exit For
End If
Else
' dieu kien ve chuoi
sArr = TmpArr(i, VarCrit(0, col))
If opt = 3 Then
' chap nhan
res = sArr Like VarCrit(2, col)
Else
' phu nhan
res = Not (sArr Like VarCrit(2, col))
End If
End If
If res = Not arg_and Then Exit For
Next col
If res Then
ReDim Preserve Tmp(0 To count)
Tmp(count) = i
count = count + 1
End If
Next i
' nếu trong mang tmp có dữ liệu là các chỉ số dòng được chọn thì ...
If count > 0 Then
' 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(LBoundTmpArr To UBound(Tmp) + LBoundTmpArr - HasTitle, 1 To UBoundTmpArr2)
' ghi các dòng của mảng nguồn mà có chỉ số là các phần tử cua tmp (tức các dòng được lấy) vào mảng Arr
For i = LBoundTmpArr - HasTitle To UBound(Tmp) + LBoundTmpArr - HasTitle
TmpcurrRow = Tmp(i - LBoundTmpArr + HasTitle)
For j = 1 To UBoundTmpArr2
Arr(i, j) = TmpArr(TmpcurrRow, 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 = 1 To UBoundTmpArr2
Arr(LBoundTmpArr, j) = TmpArr(LBoundTmpArr, j)
Next
End If
End If
' trả về mảng các dòng được chọn - lọc
MyFilter2DArray = Arr
End Function
[/GPECODE]