Filter Array 2D theo nhiều điều kiện (1 người xem)

Liên hệ QC

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

Ngô Hải Đăng

Thành viên hoạt động
Tham gia
31/8/17
Bài viết
183
Được thích
247
Giới tính
Nam
Hàm nhận 2 tham số iArray (Mảng hoặc Range) và iFilter as String (điều kiện Filter)
Các điều kiện được nối với nhau bởi OR, AND, ]OR[, ]AND[ theo mức độ ưu tiên từ cao đến thấp như sau: ]AND[ >> ]OR[ >> AND >> OR.
Các toán tử so sánh gồm: LIKE, !LIKE, <, <=, >, >=, =, <>. Trong đó LIKE và !LIKE dùng cho Text và Text phải được đặt trong 2 dấu nháy đơn (Ví dụ: 'Giải pháp Excel')
Chuỗi Filter được viết theo cú pháp như sau: [5] > 100 AND [3] LIKE '*GPE*'
Trong đó[5] và [3] là cột cần Filter, các toán tử so sánh và các phép nối OR AND đều phải cách ra 1 khoảng trắng.
Trường hợp cần so sánh ngày thì ta phải thêm # trước ngày cần so sánh (Ví dụ: [1] > #21/12/2020)
Trường hợp có sử dụng công thức thì phải thêm ? đứng trước (Ví dụ: ?[3]*[4] > 1000000 hoặc là ?Year([1]) = 2020 hoặc là ?Left([2],3) = 'GPE')

Code trong Module
PHP:
Function FilterArray2D(ByVal iArray, ByVal iFilter As String)
  Dim x&, y&, z&, minY&, maxY&, minX&, maxX&, sF$
  Dim yI(), xF(), aX

  ReDim aX(1 To 1, 1 To 1)
  If iFilter = "" Then
    aX(1, 1) = "Không có Filter..."
  Else
    If TypeName(iArray) = "Range" Then iArray = iArray.Value
    MakeFilter iFilter
    minX = LBound(iArray, 2): maxX = UBound(iArray, 2)
    For x = 1 To maxX - minX + 1
      If InStr(1, iFilter, "[" & vbBack & vbBack & x & vbBack & vbBack & "]", vbTextCompare) > 0 Then
        z = z + 1: ReDim Preserve xF(1 To z): xF(z) = x
      End If
    Next x
    If z = 0 Then
      aX(1, 1) = "Filter sai..."
    Else
      z = 0
      minY = LBound(iArray, 1): maxY = UBound(iArray, 1)
      For y = minY To maxY
        sF = iFilter
        For x = 1 To UBound(xF)
          sF = Replace(sF, "[" & vbBack & vbBack & xF(x) & vbBack & vbBack & "]", GetValueArray(iArray(y, xF(x) - 1 + minX)), , , vbTextCompare)
        Next x
        If CheckFilter(sF) Then z = z + 1: ReDim Preserve yI(1 To z): yI(z) = y
      Next y
      If z = 0 Then
        aX(1, 1) = "Không tìm ra..."
      Else
        ReDim aX(1 To z, 1 To maxX - minX + 1)
        For y = 1 To z
          For x = 1 To maxX - minX + 1
            aX(y, x) = iArray(yI(y), x - 1 + minX)
          Next x
        Next y
      End If
    End If
  End If
  FilterArray2D = aX
End Function

Private Sub MakeFilter(iFilter As String)
  Dim xBeginText&, xEndText&, sText$, x&, aCompare

  iFilter = WorksheetFunction.Trim(iFilter)
  iFilter = Replace(iFilter, "[", "[" & vbBack & vbBack)
  iFilter = Replace(iFilter, "]", vbBack & vbBack & "]")
  iFilter = Replace(iFilter, " ", vbBack, , , vbTextCompare)
  iFilter = Replace(iFilter, vbBack & vbBack & vbBack, vbBack)

  xBeginText = InStr(1, iFilter, "'") + 1
  While xBeginText > 1
    xEndText = InStr(xBeginText, iFilter, "'") + 1
    sText = Mid(iFilter, xBeginText, xEndText - xBeginText)
    iFilter = Replace(iFilter, sText, Replace(sText, vbBack & vbBack, ""))
    iFilter = Replace(iFilter, sText, Replace(sText, vbBack, " "))
    xBeginText = InStr(xEndText, iFilter, "'") + 1
  Wend

  aCompare = Array("!like", "<=", ">=", "<>", "like", "<", ">", "=")
  For x = 0 To UBound(aCompare)
    iFilter = Replace(iFilter, vbBack & aCompare(x) & vbBack, vbBack & x & vbBack, , , vbTextCompare)
  Next x
End Sub

Private Function GetValueArray(iValue)
  Select Case TypeName(iValue)
    Case Is = "String", "Null", "Empty", "Error": GetValueArray = "'" & CStr(iValue) & "'"
    Case Else: GetValueArray = CDbl(iValue)
  End Select
End Function

Private Function CheckFilter(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack & "]AND[" & vbBack, , vbTextCompare)
  Dim x&
  For x = LBound(aF) To UBound(aF)
    If Not CheckFilter1(aF(x)) Then Exit Function
  Next x
  CheckFilter = True
End Function

Private Function CheckFilter1(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack & "]OR[" & vbBack, , vbTextCompare)
  Dim x&
  For x = LBound(aF) To UBound(aF)
    If CheckFilter2(aF(x)) Then CheckFilter1 = True: Exit Function
  Next x
End Function

Private Function CheckFilter2(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack & "AND" & vbBack, , vbTextCompare)
  Dim x&
  For x = LBound(aF) To UBound(aF)
    If Not CheckFilter3(aF(x)) Then Exit Function
  Next x
  CheckFilter2 = True
End Function

Private Function CheckFilter3(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack & "OR" & vbBack, , vbTextCompare)
  Dim x&
  For x = LBound(aF) To UBound(aF)
    If CheckFilter4(aF(x)) Then CheckFilter3 = True: Exit Function
  Next x
End Function

Private Function CheckFilter4(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack)
  Dim u1, u2
  u1 = GetValueFilter(aF(0)): If IsArray(u1) Then Exit Function
  u2 = GetValueFilter(aF(2)): If IsArray(u2) Then Exit Function
  Select Case aF(1)
    Case Is = 0: CheckFilter4 = Not u1 Like u2
    Case Is = 1: CheckFilter4 = u1 <= u2
    Case Is = 2: CheckFilter4 = u1 >= u2
    Case Is = 3: CheckFilter4 = u1 <> u2
    Case Is = 4: CheckFilter4 = u1 Like u2
    Case Is = 5: CheckFilter4 = u1 < u2
    Case Is = 6: CheckFilter4 = u1 > u2
    Case Is = 7: CheckFilter4 = u1 = u2
  End Select
End Function

Private Function GetValueFilter(ByVal iString As String)
  On Error GoTo HError
  Select Case Left$(iString, 1)
    Case Is = "'": GetValueFilter = Mid(iString, 2, Len(iString) - 2)
    Case Is = "?": GetValueFilter = Evaluate("=" & Mid(iString, 2))
    Case Is = "#": GetValueFilter = CDbl(CDate(Mid(Replace(iString, "'", ""), 2)))
    Case Else: GetValueFilter = Val(iString)
  End Select
  Exit Function
HError:
GetValueFilter = Array(1)
End Function

Code Test
PHP:
Sub TestFilterArray2D()
  Dim sFilter$, rData As Range, rResult As Range, aX, xTimer!
  xTimer = Timer
  'Dieu kien Filter
  sFilter = "[2] like 'KH*' and [5] like 'Kg' and [8] > 0"
  'Chon vung Du lieu can Filter
  Set rData = Sheet3.[A3:N9601]
  'Chon Cell de gan ket qua
  Set rResult = Sheet3.[P3]
  aX = FilterArray2D(rData.Value, sFilter)
  Application.ScreenUpdating = False
  rResult.Resize(rData.Rows.Count, rData.Columns.Count).ClearContents
  rResult.Resize(UBound(aX, 1), UBound(aX, 2)) = aX
  Application.ScreenUpdating = True
  MsgBox "Time is: " & Timer - xTimer
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Code dùng ngon lành. Cảm ơn chủ thớt!
 
Upvote 0
Anh cho em Vân hỏi với là với cách này có thể lựa chọn được cột muốn hiển thị ra kết quả không ạ ??

Em Vân cảm ơn anh ạ !
 
Upvote 0
Anh cho em Vân hỏi với là với cách này có thể lựa chọn được cột muốn hiển thị ra kết quả không ạ ??

Em Vân cảm ơn anh ạ !
Hiện tại thì chưa cho chọn cột hiển thị ra kết quả nhưng nếu muốn thêm tùy chọn này vào thì cũng không khó, hoặc là dữ liệu đầu vào mình loại trước những cột nào ko cần filter cũng được.
 
Upvote 0
Hàm nhận 2 tham số iArray (Mảng hoặc Range) và iFilter as String (điều kiện Filter)
Các điều kiện được nối với nhau bởi OR, AND, ]OR[, ]AND[
Các toán tử so sánh gồm LIKE, !LIKE, <, <=, >, >=, =, <>. Trong đó LIKE và !LIKE dùng cho Text và Text phải được đặt trong 2 dấu nháy đơn (Ví dụ: 'Giải pháp Excel')
Chuỗi Filter được viết theo cú pháp như sau: [5] > 100 AND [3] LIKE '*GPE*'
Trong đó[5] và [3] là cột cần Filter, các toán tử so sánh và các phép nối OR AND đều phải cách ra 1 khoảng trắng.
Trường hợp cần so sánh ngày thì ta phải thêm # trước ngày cần so sánh (Ví dụ: [1] > #21/12/2020)
Trường hợp có sử dụng công thức thì phải thêm ? đứng trước (Ví dụ: ?[3]*[4] > 1000000 hoặc là ?Year([1]) = 2020 hoặc là ?Left([2],3) = 'GPE')

Code trong Module
PHP:
Function FilterArray2D(ByVal iArray, ByVal iFilter As String)
  Dim x&, y&, z&, minY&, maxY&, minX&, maxX&, sF$
  Dim yI(), xF(), aX

  ReDim aX(1 To 1, 1 To 1)
  If iFilter = "" Then
    aX(1, 1) = "Không có Filter..."
  Else
    If TypeName(iArray) = "Range" Then iArray = iArray.Value
    MakeFilter iFilter
    minX = LBound(iArray, 2): maxX = UBound(iArray, 2)
    For x = 1 To maxX - minX + 1
      If InStr(1, iFilter, "[" & vbBack & vbBack & x & vbBack & vbBack & "]", vbTextCompare) > 0 Then
        z = z + 1: ReDim Preserve xF(1 To z): xF(z) = x
      End If
    Next x
    If z = 0 Then
      aX(1, 1) = "Filter sai..."
    Else
      z = 0
      minY = LBound(iArray, 1): maxY = UBound(iArray, 1)
      For y = minY To maxY
        sF = iFilter
        For x = 1 To UBound(xF)
          sF = Replace(sF, "[" & vbBack & vbBack & xF(x) & vbBack & vbBack & "]", GetValueArray(iArray(y, xF(x) - 1 + minX)), , , vbTextCompare)
        Next x
        If CheckFilter(sF) Then z = z + 1: ReDim Preserve yI(1 To z): yI(z) = y
      Next y
      If z = 0 Then
        aX(1, 1) = "Không tìm ra..."
      Else
        ReDim aX(1 To z, 1 To maxX - minX + 1)
        For y = 1 To z
          For x = 1 To maxX - minX + 1
            aX(y, x) = iArray(yI(y), x - 1 + minX)
          Next x
        Next y
      End If
    End If
  End If
  FilterArray2D = aX
End Function

Private Sub MakeFilter(iFilter As String)
  Dim xBeginText&, xEndText&, sText$, x&, aCompare

  iFilter = WorksheetFunction.Trim(iFilter)
  iFilter = Replace(iFilter, "[", "[" & vbBack & vbBack)
  iFilter = Replace(iFilter, "]", vbBack & vbBack & "]")
  iFilter = Replace(iFilter, " ", vbBack, , , vbTextCompare)
  iFilter = Replace(iFilter, vbBack & vbBack & vbBack, vbBack)

  xBeginText = InStr(1, iFilter, "'") + 1
  While xBeginText > 1
    xEndText = InStr(xBeginText, iFilter, "'") + 1
    sText = Mid(iFilter, xBeginText, xEndText - xBeginText)
    iFilter = Replace(iFilter, sText, Replace(sText, vbBack & vbBack, ""))
    iFilter = Replace(iFilter, sText, Replace(sText, vbBack, " "))
    xBeginText = InStr(xEndText, iFilter, "'") + 1
  Wend

  aCompare = Array("!like", "<=", ">=", "<>", "like", "<", ">", "=")
  For x = 0 To UBound(aCompare)
    iFilter = Replace(iFilter, vbBack & aCompare(x) & vbBack, vbBack & x & vbBack, , , vbTextCompare)
  Next x
End Sub

Private Function GetValueArray(iValue)
  Select Case TypeName(iValue)
    Case Is = "String", "Null", "Empty", "Error": GetValueArray = "'" & CStr(iValue) & "'"
    Case Else: GetValueArray = CDbl(iValue)
  End Select
End Function

Private Function CheckFilter(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack & "]AND[" & vbBack, , vbTextCompare)
  Dim x&
  For x = LBound(aF) To UBound(aF)
    If Not CheckFilter1(aF(x)) Then Exit Function
  Next x
  CheckFilter = True
End Function

Private Function CheckFilter1(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack & "]OR[" & vbBack, , vbTextCompare)
  Dim x&
  For x = LBound(aF) To UBound(aF)
    If CheckFilter2(aF(x)) Then CheckFilter1 = True: Exit Function
  Next x
End Function

Private Function CheckFilter2(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack & "AND" & vbBack, , vbTextCompare)
  Dim x&
  For x = LBound(aF) To UBound(aF)
    If Not CheckFilter3(aF(x)) Then Exit Function
  Next x
  CheckFilter2 = True
End Function

Private Function CheckFilter3(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack & "OR" & vbBack, , vbTextCompare)
  Dim x&
  For x = LBound(aF) To UBound(aF)
    If CheckFilter4(aF(x)) Then CheckFilter3 = True: Exit Function
  Next x
End Function

Private Function CheckFilter4(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack)
  Dim u1, u2
  u1 = GetValueFilter(aF(0))
  u2 = GetValueFilter(aF(2))
  Select Case aF(1)
    Case Is = 0: CheckFilter4 = Not u1 Like u2
    Case Is = 1: CheckFilter4 = u1 <= u2
    Case Is = 2: CheckFilter4 = u1 >= u2
    Case Is = 3: CheckFilter4 = u1 <> u2
    Case Is = 4: CheckFilter4 = u1 Like u2
    Case Is = 5: CheckFilter4 = u1 < u2
    Case Is = 6: CheckFilter4 = u1 > u2
    Case Is = 7: CheckFilter4 = u1 = u2
  End Select
End Function

Private Function GetValueFilter(ByVal iString As String)
  Select Case Left$(iString, 1)
    Case Is = "'": GetValueFilter = Mid(iString, 2, Len(iString) - 2)
    Case Is = "?": GetValueFilter = Evaluate("=" & Mid(iString, 2))
    Case Is = "#": GetValueFilter = CDbl(CDate(Mid(iString, 2)))
    Case Else: GetValueFilter = Val(iString)
  End Select
End Function

Code Test
PHP:
Sub TestFilterArray2D()
  Dim sFilter$, rData As Range, rResult As Range, aX, xTimer!
  xTimer = Timer
  'Dieu kien Filter
  sFilter = "[2] like 'KH*' and [5] like 'Kg' and [8] > 0"
  'Chon vung Du lieu can Filter
  Set rData = Sheet3.[A3:N9601]
  'Chon Cell de gan ket qua
  Set rResult = Sheet3.[P3]
  aX = FilterArray2D(rData.Value, sFilter)
  Application.ScreenUpdating = False
  rResult.Resize(rData.Rows.Count, rData.Columns.Count).ClearContents
  rResult.Resize(UBound(aX, 1), UBound(aX, 2)) = aX
  Application.ScreenUpdating = True
  MsgBox "Time is: " & Timer - xTimer
End Sub
Sẽ bị lỗi nếu như cột 1 không phải là kiểu ngày tháng, nên xử lý bẫy lỗi trường hợp này
 
Upvote 0
Hình như công cụ AdvanceFilter đã không còn tác dụng sau khi có code tuyệt phẩm này
 
Upvote 0
Sẽ bị lỗi nếu như cột 1 không phải là kiểu ngày tháng, nên xử lý bẫy lỗi trường hợp này

Sửa lại 2 Function này chút xíu
PHP:
Private Function CheckFilter4(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack)
  Dim u1, u2
  u1 = GetValueFilter(aF(0))
  u2 = GetValueFilter(aF(2))
  Select Case aF(1)
    Case Is = 0: CheckFilter4 = Not u1 Like u2
    Case Is = 1: CheckFilter4 = u1 <= u2
    Case Is = 2: CheckFilter4 = u1 >= u2
    Case Is = 3: CheckFilter4 = u1 <> u2
    Case Is = 4: CheckFilter4 = u1 Like u2
    Case Is = 5: CheckFilter4 = u1 < u2
    Case Is = 6: CheckFilter4 = u1 > u2
    Case Is = 7: CheckFilter4 = u1 = u2
  End Select
End Function

Private Function GetValueFilter(ByVal iString As String)
  Select Case Left$(iString, 1)
    Case Is = "'": GetValueFilter = Mid(iString, 2, Len(iString) - 2)
    Case Is = "?": GetValueFilter = Evaluate("=" & Mid(iString, 2))
    Case Is = "#": GetValueFilter = CDbl(CDate(Mid(iString, 2)))
    Case Else: GetValueFilter = Val(iString)
  End Select
End Function

Sửa thành như vậy
PHP:
Private Function CheckFilter4(ByVal iFilter As String) As Boolean
  Dim aF: aF = Split(iFilter, vbBack)
  Dim u1, u2
  u1 = GetValueFilter(aF(0)): If IsArray(u1) Then Exit Function
  u2 = GetValueFilter(aF(2)): If IsArray(u2) Then Exit Function
  Select Case aF(1)
    Case Is = 0: CheckFilter4 = Not u1 Like u2
    Case Is = 1: CheckFilter4 = u1 <= u2
    Case Is = 2: CheckFilter4 = u1 >= u2
    Case Is = 3: CheckFilter4 = u1 <> u2
    Case Is = 4: CheckFilter4 = u1 Like u2
    Case Is = 5: CheckFilter4 = u1 < u2
    Case Is = 6: CheckFilter4 = u1 > u2
    Case Is = 7: CheckFilter4 = u1 = u2
  End Select
End Function

Private Function GetValueFilter(ByVal iString As String)
  On Error GoTo HError
  Select Case Left$(iString, 1)
    Case Is = "'": GetValueFilter = Mid(iString, 2, Len(iString) - 2)
    Case Is = "?": GetValueFilter = Evaluate("=" & Mid(iString, 2))
    Case Is = "#": GetValueFilter = CDbl(CDate(Mid(Replace(iString, "'", ""), 2)))
    Case Else: GetValueFilter = Val(iString)
  End Select
  Exit Function
HError:
GetValueFilter = Array(1)
End Function
 
Upvote 0
Hình như công cụ AdvanceFilter đã không còn tác dụng sau khi có code tuyệt phẩm này
Đâu có sao, càng nhiều công cụ càng tốt.
Chỉ có điều là cỡ đầu óc bùn như tôi 3 tháng sau quên mất. Mà nhìn code không có chú thích thế này, 3 tháng sau quả là ngại không dám dùng.
Nếu tôi muốn dùng thì phải copy code vào thư viện riêng. Sau đó cóp luôn cái phần chỉ dẫn cách dùng ở đầu bài #1 vào làm chú thích cách sử dụng...
Về thuật toán thì quên đi. Ra đúng biết đúng, ra sai chưa chắc biết sai. Do mình không biết cách dùng, do thuật toán sai, hay do code sai?
 
Upvote 0
ko biết có siêu việt hơn cái AdvanceFilter của bill ko nữa ...
thấy code khủng quá nên làm biếng dòm .. vì có cố dòm cũng ko có hiểu nên làm biếng đó mà -0-0-0-
 
Upvote 0
Mắc mớ gì đòi hỏi nó phải hơn công cụ có sẵn của MS.
Nó chỉ đưa ra công việc mà MS không làm. Chẳng phải đấy là nhiệm vụ của addins hay sao?
Cái nó làm mà MS không làm là parse chuỗi điều kiện.
Cái mà thớt chủ quan không giải thích là luật ưu tiên toán tử: có theo luật chung hay không? tức là and ưu tiên trước or?
Và theo tôi đọc cách chỉ dẫn sử dụng thì không có phần giải thích cách dùng dấu ngoặc (). Parse chuỗi mà không có dấu ngoặc thì là thiếu sót trầm trọng.
 
Upvote 0
Hình như công cụ AdvanceFilter đã không còn tác dụng sau khi có code tuyệt phẩm này
Anh quá khen rồi, em xem đây là động lực để viết thêm được những code có ích khác sau này.
Đâu có sao, càng nhiều công cụ càng tốt.
Chỉ có điều là cỡ đầu óc bùn như tôi 3 tháng sau quên mất. Mà nhìn code không có chú thích thế này, 3 tháng sau quả là ngại không dám dùng.
Nếu tôi muốn dùng thì phải copy code vào thư viện riêng. Sau đó cóp luôn cái phần chỉ dẫn cách dùng ở đầu bài #1 vào làm chú thích cách sử dụng...
Về thuật toán thì quên đi. Ra đúng biết đúng, ra sai chưa chắc biết sai. Do mình không biết cách dùng, do thuật toán sai, hay do code sai?
Cái này sử dụng nhiều nên chưa quên được đâu anh, nhưng chắc cũng phải thêm ghi chú cho chắc ăn.
ko biết có siêu việt hơn cái AdvanceFilter của bill ko nữa ...
thấy code khủng quá nên làm biếng dòm .. vì có cố dòm cũng ko có hiểu nên làm biếng đó mà -0-0-0-
Thêm được cái nhận dữ liệu đầu vào là Array thôi anh, còn chức năng vẫn y chang
Bài đã được tự động gộp:

Mắc mớ gì đòi hỏi nó phải hơn công cụ có sẵn của MS.
Nó chỉ đưa ra công việc mà MS không làm. Chẳng phải đấy là nhiệm vụ của addins hay sao?
Cái nó làm mà MS không làm là parse chuỗi điều kiện.
Cái mà thớt chủ quan không giải thích là luật ưu tiên toán tử: có theo luật chung hay không? tức là and ưu tiên trước or?
Và theo tôi đọc cách chỉ dẫn sử dụng thì không có phần giải thích cách dùng dấu ngoặc (). Parse chuỗi mà không có dấu ngoặc thì là thiếu sót trầm trọng.
Nó sẽ ưu tiên AND trước rồi mới đến OR, nếu muốn ưu tiên OR trước thì phải sử dụng ]OR[. Trong nội dung code này thì em chỉ sử dụng 4 cấp theo mức độ ưu tiên từ cao đến thấp như sau: ]AND[ >> ]OR[ >> AND >> OR. Phần này đúng là có thiếu sót, để em cập nhật lại trong nội dung bài số 1.
 
Lần chỉnh sửa cuối:
Upvote 0
Trời, khó thật.
Tôi cứ ngỡ ][ có nghĩa là NOT
]OR[ nghĩa là NOR, và ]AND[ nghĩa là NAND
 
Upvote 0
Trời, khó thật.
Tôi cứ ngỡ ][ có nghĩa là NOT
]OR[ nghĩa là NOR, và ]AND[ nghĩa là NAND
Lúc đầu em chỉ có AND với OR thôi. Nhưng khi gặp trường hợp (A AND B) OR (C AND D) thì em mới nghĩ đến việc thêm ]OR[ vào. Lý do em để cặp ][ là để ... gõ cho nhanh :D
 
Upvote 0
Bây giờ bạn biện chứng cho biết, tại sao không dùng DAO.Recorset để filter?
Ví dụ tôi vẫn dùng cái giao diện (interface) như bạn tức là nạp môt mảng, và một filter string. Nhưng bên trong code, tôi dùng Advanced Filter hoặc Recordset filter?
 
Upvote 0
Bây giờ bạn biện chứng cho biết, tại sao không dùng DAO.Recorset để filter?
Ví dụ tôi vẫn dùng cái giao diện (interface) như bạn tức là nạp môt mảng, và một filter string. Nhưng bên trong code, tôi dùng Advanced Filter hoặc Recordset filter?
Thứ nhất là vì Recordset đã có nhiều bài hướng dẫn trên diễn đàn, Advanced Filter cũng vậy nên nếu em viết lại thì xem như thừa vì cũng không có gì mới so với các bài viết trước. Thứ hai là giải thuật Filter Array trên diễn đàn cũng có nhưng đã rất lâu và em muốn viết 1 giải thuật khác tốt hơn. Chỉ như vậy thôi.
 
Upvote 0
Thứ nhất là vì Recordset đã có nhiều bài hướng dẫn trên diễn đàn, Advanced Filter cũng vậy nên nếu em viết lại thì xem như thừa vì cũng không có gì mới so với các bài viết trước. Thứ hai là giải thuật Filter Array trên diễn đàn cũng có nhưng đã rất lâu và em muốn viết 1 giải thuật khác tốt hơn. Chỉ như vậy thôi.
Theo tôi thì bạn nên khai thác cái Recordset thì sẽ đáp ứng được yêu cầu.
 
Upvote 0
Cách viết code của bạn khiến giải thuật dính liền với giao diện.
Đối với các code mì ăn liền như hầu hết các code viết giúp người khác ở đây thì làm như vậy rất nhanh và hiệu quả.
Với code viết để dùng trong thư viện thì cách sắp xếp code cũng là một công việc quan trọng cần thiết kế.

Ở bài #19, tôi cố tình hỏi như thế là để xem bạn có cách tách rời giải thuật ra. Điển hình là có cái hàm chính, gọi hàm A để phân tích giao diện, gọi hàm B để lấy dữ liệu và làm việc, gọi hàm C để trình bày đầu ra. Kiểu như MVC của dot net vậy. Với thiết kế này, hàm B có đủ tự do để chọn lựa giải thuật tốt nhất hoặc tích nghi với hoàn cảnh nhất. (toi chỉ quan trọng ở A,B,C thôi. Chuyện B gọi b2 là chuyện riêng của nó)

Trên diễn đàn này, tôi chỉ thấy có một bạn làm chuyện này. Nhưng rất tiếc là code mang tính chất biểu diễn nhiều hơn thực dụng cho nên nhét một đống options vào làm rối cả code.
 
Upvote 0
Theo tôi thì bạn nên khai thác cái Recordset thì sẽ đáp ứng được yêu cầu.
Cho mình hỏi thêm là trong Recordset mình có thể Filter với điều kiện Field1 <>= Field2 hay chỉ Filter với 1 giá trị cố định.

Cách viết code của bạn khiến giải thuật dính liền với giao diện.
Đối với các code mì ăn liền như hầu hết các code viết giúp người khác ở đây thì làm như vậy rất nhanh và hiệu quả.
Với code viết để dùng trong thư viện thì cách sắp xếp code cũng là một công việc quan trọng cần thiết kế.

Ở bài #19, tôi cố tình hỏi như thế là để xem bạn có cách tách rời giải thuật ra. Điển hình là có cái hàm chính, gọi hàm A để phân tích giao diện, gọi hàm B để lấy dữ liệu và làm việc, gọi hàm C để trình bày đầu ra. Kiểu như MVC của dot net vậy. Với thiết kế này, hàm B có đủ tự do để chọn lựa giải thuật tốt nhất hoặc tích nghi với hoàn cảnh nhất. (toi chỉ quan trọng ở A,B,C thôi. Chuyện B gọi b2 là chuyện riêng của nó)

Trên diễn đàn này, tôi chỉ thấy có một bạn làm chuyện này. Nhưng rất tiếc là code mang tính chất biểu diễn nhiều hơn thực dụng cho nên nhét một đống options vào làm rối cả code.
Code của em có thể tách ra được theo như gợi ý của anh, em sẽ viết lại theo gợi ý này.
 
Upvote 0
Upvote 0
@Ngô Hải Đăng sử dụng ado lấy nó vào 1 array xong duyệt nó mà tính toán đi còn dễ làm ăn đấy
SQL thuần Ado cà chua lắm ... mặc dù tôi viết ra cái SQL úp GPE đó mà nhiều câu lệnh SQL thuần ado cũng tịt toàn tập luôn những lúc như thế tôi cho vào 1 array xong xử lý nó quá ngon lành và nhẹ nhàng

thêm 2 dòng lặp tốn thêm mấy giây mà mình làm chủ nó .... còn hơn nó làm chủ mình !?

Thế thôi cho nhẹ đầu
 
Upvote 0
@Ngô Hải Đăng sử dụng ado lấy nó vào 1 array xong duyệt nó mà tính toán đi còn dễ làm ăn đấy
SQL thuần Ado cà chua lắm ... mặc dù tôi viết ra cái SQL úp GPE đó mà nhiều câu lệnh SQL thuần ado cũng tịt toàn tập luôn những lúc như thế tôi cho vào 1 array xong xử lý nó quá ngon lành và nhẹ nhàng

thêm 2 dòng lặp tốn thêm mấy giây mà mình làm chủ nó .... còn hơn nó làm chủ mình !?

Thế thôi cho nhẹ đầu
Không vòng lặp và nhìn cũng không mấy cà chua. Chạy trên 365

1608623203849.png
 
Upvote 0
Upvote 0
Cho mình hỏi thêm là trong Recordset mình có thể Filter với điều kiện Field1 <>= Field2 hay chỉ Filter với 1 giá trị cố định.
Sau khi đưa vào Recordset nếu không dùng vòng lặp để xử lý tiếp thì chỉ có thể như sau (*):

1608623671165.png

(*) Kết quả được chạy ở Office 365
 
Upvote 0
Recordset cần sử dụng là của DAO chứ không phải của ADO.
ADO chỉ có hiệu quả khi được dùng để lấy dữ liệu ở nơi khác. Ngày nay, với sự phát triển của Power Query thì vị trí của ADO càng ít đi.
Ở đây, khi nói chuyện "giải thuật" tôi đã giả sử giải thuật đã được đưa vào sub riêng, chỉ làm việc với Array. Việc đưa dữ liệu từ range vào Array là chuyện của sub tiếp xúc với giao diện, lấy unput đưa vào cho sub làm việc với 2D array (đúng theo tiêu đề).
 
Upvote 0
Recordset cần sử dụng là của DAO chứ không phải của ADO.
ADO chỉ có hiệu quả khi được dùng để lấy dữ liệu ở nơi khác. Ngày nay, với sự phát triển của Power Query thì vị trí của ADO càng ít đi.
Ở đây, khi nói chuyện "giải thuật" tôi đã giả sử giải thuật đã được đưa vào sub riêng, chỉ làm việc với Array. Việc đưa dữ liệu từ range vào Array là chuyện của sub tiếp xúc với giao diện, lấy unput đưa vào cho sub làm việc với 2D array (đúng theo tiêu đề).
Bài #28 em dùng cách là lấy 1 vùng dữ liệu nguồn chuyển thành mảng rồi từ mảng đó đưa nó vào Recordset. Sau đó thực hiện lọc, sắp xếp và trả về kết quả.
 
Upvote 0

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

Back
Top Bottom