Các câu hỏi về mảng trong VBA (Array)

Liên hệ QC

viehoai

Thành viên gắn bó
Tham gia
22/5/09
Bài viết
2,599
Được thích
2,908
Xin các anh chị giúp đỡ Code Gán các giá trị của một Range là các phần tử của Mãng
Ví dụ: Tôi có các giá trị của Range("A1:A10"). Tôi muốn viết code để gán giá trị của các cells từ A1:A10 là các phần tử của Mãng Arr chẳn hạn.
Xin cảm ơn các anh chị
 
Bài toán Tổng hợp như hình ở dưới, vùng Font chữ màu đen là dữ liệu đầu vào, vùng đỏ là minh họa kết quả sau khi chạy Code. Tuy vậy, kết quả tổng hợp chưa đúng, rất mong được giúp đỡ
Dữ liệu nhiều, bạn nên cho file đính kèm lên đây luôn nhé
 
Upvote 0
Xin gửi file đính kèm (vì máy ở nhà bị chuột cắn mất một số sợi con của dây mạng nên nó không thực hiện được một số chức năng trên diễn đàn, không sửa đính kèm file theo bài trước)

PHP:
Sub Tonghop()
Dim DL(), KQ(), i As Long, j As Long, fDate, eDate
Set Dic = CreateObject("Scripting.Dictionary")
DL = Range([A5], [E65000].End(xlUp)).Value
ReDim KQ(1 To UBound(DL, 1), 1 To UBound(DL, 2))
fDate = [H1].Value
eDate = [H2].Value
For i = 1 To UBound(DL, 1) Step 1
    If DL(i, 1) >= fDate And DL(i, 1) <= eDate Then 
        If Not Dic.Exists(DL(i, 2)) Then
            j = j + 1
            Tmp = DL(i, 2)
            Dic.Add Tmp, j
            KQ(Dic.Item(Tmp), 1) = DL(i, 2)
            KQ(Dic.Item(Tmp), 2) = DL(i, 3)
            KQ(Dic.Item(Tmp), 3) = DL(i, 4)
            KQ(Dic.Item(Tmp), 4) = DL(i, 5)
        ElseIf Dic.Exists(DL(i, 1)) Then            'chỗ này phải sửa thành ElseIf Dic.Exists(DL(i, 2)) Then mới đúng
            KQ(Dic.Item(Tmp), 1) = DL(i, 2)
            KQ(Dic.Item(Tmp), 2) = DL(i, 3)
            KQ(Dic.Item(Tmp), 3) = KQ(Dic.Item(Tmp), 3) + DL(i, 4)
            KQ(Dic.Item(Tmp), 4) = KQ(Dic.Item(Tmp), 4) + DL(i, 5)
        End If
    End If
Next
Range("G5").Resize(j, 4).Value = KQ
End Sub

-------------
Phát hiện ra rồi thày ah: ElseIf Dic.Exists(DL(i, 1)) Then nhầm, đúng ra phải là ElseIf Dic.Exists(DL(i, 2)) Then

Xin cảm ơn thày rất nhiều.
 

File đính kèm

  • Tong hop theo thoi gian.xls
    21.5 KB · Đọc: 88
Lần chỉnh sửa cuối:
Upvote 0
Nếu bài toán đổi thành bài toán Lọc: Vùng dữ liệu đầu vào sẽ được lọc (tách ra) thành nhiều Sheet theo tiêu chí mỗi Phụ liệu ở cột B được lọc ra một Sheet riêng thì cú pháp tách riêng thành các Sheet nó phải viết thế nào hả thày?
 
Upvote 0
Bài toán Tổng hợp như hình ở dưới, vùng Font chữ màu đen là dữ liệu đầu vào, vùng đỏ là minh họa kết quả sau khi chạy Code. Tuy vậy, kết quả tổng hợp chưa đúng, rất mong được giúp đỡ
Code cụ thể nhau sau

PHP:
Sub Tonghop()
Dim DL(), KQ(), i As Long, j As Long, fDate, eDate
Set Dic = CreateObject("Scripting.Dictionary")
DL = Range([A5], [E65000].End(xlUp)).Value
ReDim KQ(1 To UBound(DL, 1), 1 To UBound(DL, 2))
fDate = [H1].Value
eDate = [H2].Value
For i = 1 To UBound(DL, 1) Step 1
    If DL(i, 1) > fDate And DL(i, 1) <= eDate Then
        If Not Dic.Exists(DL(i, 2)) Then
            j = j + 1
            Tmp = DL(i, 2)
            Dic.Add Tmp, j
            KQ(Dic.Item(Tmp), 1) = DL(i, 2)
            KQ(Dic.Item(Tmp), 2) = DL(i, 3)
            KQ(Dic.Item(Tmp), 3) = DL(i, 4)
            KQ(Dic.Item(Tmp), 4) = DL(i, 5)
        ElseIf Dic.Exists(DL(i, 1)) Then
            KQ(Dic.Item(Tmp), 1) = DL(i, 2)
            KQ(Dic.Item(Tmp), 2) = DL(i, 3)
            KQ(Dic.Item(Tmp), 3) = KQ(Dic.Item(Tmp), 3) + DL(i, 4)
            KQ(Dic.Item(Tmp), 4) = KQ(Dic.Item(Tmp), 4) + DL(i, 5)
        End If
    End If
Next
Range("G5").Resize(j, 4).Value = KQ
End Sub
Sai nhiều chổ quá, vầy mới đúng
PHP:
Sub Tonghop()
  Dim DL(), KQ(), i As Long, j As Long, fDate, eDate, Dic As Object, tmp As String
  Set Dic = CreateObject("Scripting.Dictionary")
  DL = Range([A5], [E65000].End(xlUp)).Value
  ReDim KQ(1 To UBound(DL, 1), 1 To UBound(DL, 2))
  fDate = [H1].Value
  eDate = [H2].Value
  For i = 1 To UBound(DL, 1) Step 1
    If CStr(DL(i, 2)) <> "" Then
      If DL(i, 1) >= fDate And DL(i, 1) <= eDate Then
        tmp = CStr(DL(i, 2))
        If Not Dic.Exists(tmp) Then
          j = j + 1
          Dic.Add tmp, j
          KQ(j, 1) = tmp
          KQ(j, 2) = DL(i, 3)
          KQ(j, 3) = DL(i, 4)
          KQ(j, 4) = DL(i, 5)
        Else
          KQ(Dic.Item(tmp), 3) = KQ(Dic.Item(tmp), 3) + DL(i, 4)
          KQ(Dic.Item(tmp), 4) = KQ(Dic.Item(tmp), 4) + DL(i, 5)
        End If
      End If
    End If
  Next
  If j Then Range("G5").Resize(j, 4).Value = KQ
End Sub
Lưu ý: nhớ khai báo biến đầy đủ
 
Upvote 0
Hic đọc bài của thày mới biết bài của mình có quá nhiều lỗi sơ đẳng
- Else là đủ rồi cần chi phải ElseIf Dic.Exists(DL(i, 1)) Then dài dòng.
- Các dòng
PHP:
KQ(Dic.Item(Tmp), 1) = DL(i, 2)
            KQ(Dic.Item(Tmp), 2) = DL(i, 3)
lặp đi lặp lại 2 lần nhìn thấy nó có vẻ không ổn, thể nhưng mà cũng không biết là nó thừa để bỏ đi

Xin cảm ơn thày rất nhiều, mỗi lần thày sửa bài giúp tôi lại học được những điều rất bổ ích, tôi sẽ cố gắng thời gian tới sẽ không mắc lỗi tương tự như vầy nữa.
 
Upvote 0
Hic đọc bài của thày mới biết bài của mình có quá nhiều lỗi sơ đẳng
- Else là đủ rồi cần chi phải ElseIf Dic.Exists(DL(i, 1)) Then dài dòng.
- Các dòng
PHP:
KQ(Dic.Item(Tmp), 1) = DL(i, 2)
            KQ(Dic.Item(Tmp), 2) = DL(i, 3)
lặp đi lặp lại 2 lần nhìn thấy nó có vẻ không ổn, thể nhưng mà cũng không biết là nó thừa để bỏ đi

Xin cảm ơn thày rất nhiều, mỗi lần thày sửa bài giúp tôi lại học được những điều rất bổ ích, tôi sẽ cố gắng thời gian tới sẽ không mắc lỗi tương tự như vầy nữa.
Theo tôi có thể rút gọn code của anh NDU thêm 1 chút và những thuật toán để tối ưu code.
1/
PHP:
If CStr(DL(i, 2)) <> "" Then
Thay bằng
PHP:
If Len(CStr(DL(i, 2))) Then
2/ Và
PHP:
If DL(i, 1) >= fDate And DL(i, 1) <= eDate Then
Bằng
PHP:
If DL(i, 1) >= fDate Then
        If DL(i, 1) <= eDate Then

3/
PHP:
KQ(j, 3) = DL(i, 4)
          KQ(j, 4) = DL(i, 5)
        Else
          KQ(Dic.Item(tmp), 3) = KQ(Dic.Item(tmp), 3) + DL(i, 4)
          KQ(Dic.Item(tmp), 4) = KQ(Dic.Item(tmp), 4) + DL(i, 5)
        End If
Có thể rút gọn.
Và còn 1 chuyện nữa là có cần chuyển Date sang long, chưa kiểm tra hết.

Code mới như sau.

PHP:
Sub Tonghop1()
  Dim DL(), KQ(), i As Long, j As Long, fDate, eDate, Dic As Object, tmp As String
  Set Dic = CreateObject("Scripting.Dictionary")
  DL = Range([A5], [E65000].End(xlUp)).Value
  ReDim KQ(1 To UBound(DL, 1), 1 To UBound(DL, 2))
  fDate = [H1].Value
  eDate = [H2].Value
  For i = 1 To UBound(DL, 1) Step 1
    If Len(CStr(DL(i, 2))) Then
      If DL(i, 1) >= fDate Then
        If DL(i, 1) <= eDate Then
          tmp = CStr(DL(i, 2))
          If Not Dic.Exists(tmp) Then
            j = j + 1
            Dic.Add tmp, j
            KQ(j, 1) = tmp
            KQ(j, 2) = DL(i, 3)
          End If
          KQ(Dic.Item(tmp), 3) = KQ(Dic.Item(tmp), 3) + DL(i, 4)
          KQ(Dic.Item(tmp), 4) = KQ(Dic.Item(tmp), 4) + DL(i, 5)
        End If
      End If
    End If
  Next
  If j Then Range("G5").Resize(j, 4).Value = KQ
End Sub
Và làm xong nên có động tác Erase và set Dic=nothing
 
Upvote 0
Và làm xong nên có động tác Erase và set Dic=nothing
Cái này không cần, trừ trường hợp Array và Dic được khai báo Public (ở trên Sub)
----------------------------
Nếu bài toán đổi thành bài toán Lọc: Vùng dữ liệu đầu vào sẽ được lọc (tách ra) thành nhiều Sheet theo tiêu chí mỗi Phụ liệu ở cột B được lọc ra một Sheet riêng thì cú pháp tách riêng thành các Sheet nó phải viết thế nào hả thày?
Khó à nghen Đầu tiên bạn đổi tên Sheet Dữ Liệu thành Data, xong chạy code dưới đây:
PHP:
Sub Tonghop()
  Dim sArray, subArr(), Arr(), i As Long, n As Long, title
  Dim tmpR As Long, p As Long, lC As Long, keyArr, WshName As String
  On Error Resume Next
  Dim Dic As Object, tmp As String
  Set Dic = CreateObject("Scripting.Dictionary")
  With Sheets("Data")
    sArray = .Range("A5:E1000").Value
    title = .Range("A4:E4").Value
  End With
  ReDim subArr(1 To UBound(sArray, 1), 1 To UBound(sArray, 2) + 1)
  For i = 1 To UBound(sArray, 1)
    If CStr(sArray(i, 2)) <> "" Then
      tmp = CStr(sArray(i, 2))
      If Not Dic.Exists(tmp) Then
        n = n + 1
        Dic.Add tmp, n
        ReDim Preserve Arr(1 To n)
        subArr(1, UBound(subArr, 2)) = 1
        Arr(n) = subArr
        For lC = 1 To UBound(subArr, 2) - 1
          Arr(n)(1, lC) = sArray(i, lC)
        Next
      Else
        p = Dic.Item(tmp)
        Arr(p)(1, UBound(subArr, 2)) = Arr(p)(1, UBound(subArr, 2)) + 1
        tmpR = Arr(p)(1, UBound(subArr, 2))
        For lC = 1 To UBound(subArr, 2) - 1
          Arr(p)(tmpR, lC) = sArray(i, lC)
        Next
      End If
    End If
  Next
  If Dic.Count Then
    keyArr = Dic.Keys
    For i = 1 To Dic.Count
      WshName = CStr(keyArr(i - 1))
      If isValidWshName(WshName) Then
        If Not SheetExist(WshName) Then
          Sheets.Add(After:=Sheets(Sheets.Count)).Name = WshName
        End If
      End If
      With Sheets(WshName)
        .UsedRange.ClearContent
        .Name = keyArr(i - 1)
        .Range("A1").Resize(, UBound(sArray, 2)).Value = title
        .Range("A2").Resize(UBound(Arr(i)), lC - 1).Value = Arr(i)
      End With
    Next
  End If
End Sub
PHP:
Function SheetExist(ByVal WshName As String) As Boolean
  On Error Resume Next
  SheetExist = Not ThisWorkbook.Sheets(WshName) Is Nothing
End Function
PHP:
Function isValidWshName(ByVal WshName As String) As Boolean
  Dim i As Long, InvalidName As String
  InvalidName = ":\/?*[]"
  If Len(WshName) > 31 Or Len(WshName) = 0 Then Exit Function
  For i = 1 To Len(InvalidName)
    If InStr(WshName, Mid(InvalidName, i, 1)) Then Exit Function
  Next
  isValidWshName = True
End Function

Thử xem!
 
Lần chỉnh sửa cuối:
Upvote 0
Mã:
Khó à nghen
Đầu tiên bạn đổi tên Sheet Dữ Liệu thành Data, xong chạy code dưới đây:
PHP:
Function isValidWshName(ByVal WshName As String) As Boolean
  Dim i As Long, InvalidName As String
  InvalidName = ":\/?*[]"
  If Len(WshName) > 31 Or Len(WshName) = 0 Then Exit Function
  For i = 1 To Len(InvalidName)
    If InStr(WshName, Mid(InvalidName, i, 1)) Then Exit Function
  Next
  isValidWshName = True
End Function
Thử xem![/QUOTE]
Hay quá, cái UDF này rất hay.
Tôi đang thắc mắc, nếu dữ liệu lớn, trong quá trình tách SubArr ra sheet sợ nặng lắm không.
Tôi đề xuất theo phương án 2 for.
1/ Tạo Dic và phần Item là lấy các số dòng như là x, y, ..., n.
2/ Duyệt qua Dic và sArr lấy theo dòng theo Item của Dic trên. Xong dòng nào thì add sh.
Không biết có nhanh hơn không. Để làm thử.
Cám ơn NDU về sự chặc chẽ của Code và sự sáng tạo.
 
Upvote 0
Tôi đang thắc mắc, nếu dữ liệu lớn, trong quá trình tách SubArr ra sheet sợ nặng lắm không.
.
Cái này là mảng trong mảng:
- Mảng lớn (Arr) có tổng số phần tử = tổng số sheet
- Mỗi phần tử của mảng lớn lại là 1 mảng (subArr)
- Dữ liệu của subArr chính là dữ liệu ta sẽ gán vào sheet (tại vị trí chứa subArr)
Đằng nào cũng là xử lý mảng, tôi nghĩ chắc không chậm đâu ---> Chậm chăng là quá trình Add Sheet
 
Upvote 0
Cái này là mảng trong mảng:
- Mảng lớn (Arr) có tổng số phần tử = tổng số sheet
- Mỗi phần tử của mảng lớn lại là 1 mảng (subArr)
- Dữ liệu của subArr chính là dữ liệu ta sẽ gán vào sheet (tại vị trí chứa subArr)
Đằng nào cũng là xử lý mảng, tôi nghĩ chắc không chậm đâu ---> Chậm chăng là quá trình Add Sheet
Mình làm theo dạng gán vào ArrKQ tới đâu thì add sh liền và redim.
Ndu test giúp. Cám ơn!
PHP:
Function SheetExist(ByVal WshName As String) As Boolean
  On Error Resume Next
  SheetExist = Not ThisWorkbook.Sheets(WshName) Is Nothing
End Function
Function isValidWshName(ByVal WshName As String) As Boolean
  Dim i As Long, InvalidName As String
  InvalidName = ":\/?*[]"
  If Len(WshName) > 31 Or Len(WshName) = 0 Then Exit Function
  For i = 1 To Len(InvalidName)
    If InStr(WshName, Mid(InvalidName, i, 1)) Then Exit Function
  Next
  isValidWshName = True
End Function
Sub TonghopArr()
  Dim sArray, subArr(), Arr(), i As Long, n As Long, Title, nR&, k&, n&
  Dim tmpR As Long, p As Long, lC As Long, keyArr, WshName As String
  Dim Dic As Object, Tmp As String, ArrBP
  Dim T
  T = Timer
  Set Dic = CreateObject("Scripting.Dictionary")
  With Sheets("Data")
    sArray = .Range("A5:E1000").Value
    Title = .Range("A4:E4").Value
  End With
  ReDim ArrBP(1 To UBound(sArray, 1), 1 To 2)
  For i = 1 To UBound(sArray, 1)
    If Len(CStr(sArray(i, 2))) Then
      Tmp = CStr(sArray(i, 2))
      If Not Dic.Exists(Tmp) Then
        n = n + 1
        Dic.Add Tmp, n
        ArrBP(n, 1) = Tmp
      End If
      nR = Dic.Item(Tmp)
      If Len(ArrBP(nR, 1)) Then
        ArrBP(nR, 2) = ArrBP(nR, 2) & vbBack & i
      Else
        ArrBP(nR, 2) = i
      End If
    End If
  Next
 
  For i = 1 To n
    nR = 0
    Tmp = CStr(ArrBP(i, 2))
    aSplit = Split(Tmp, vbBack)
    ReDim subArr(1 To UBound(aSplit), 1 To UBound(sArray, 2))
    For j = 1 To UBound(aSplit)
      nR = nR + 1
      For k = 1 To UBound(sArray, 2)
        subArr(nR, k) = sArray(aSplit(j), k)
      Next k
    Next j
    WshName = CStr(ArrBP(i, 1))
    If isValidWshName(WshName) Then
      If Not SheetExist(WshName) Then
        Sheets.Add(After:=Sheets(Sheets.Count)).Name = WshName
      End If
    End If
    With Sheets(WshName)
      .UsedRange.ClearContent
      .Name = WshName
      .Range("A1").Resize(, UBound(sArray, 2)).Value = Title
      .Range("A2").Resize(UBound(aSplit), UBound(sArray, 2)) = subArr
    End With
  Next i
MsgBox Timer - T
End Sub
 
Upvote 0
ơ bỗng dưng hôm này đọc lại em lại thấy lúng túng ở đây như vậy 2 cầu lệnh
PHP:
If DL(i, 2) = Cells(1, 6) And Not Dic.Exists(DL(i, 2)) Then
        j = j + 1
        Dic.Add DL(i, 1), j
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    ElseIf DL(i, 2) = Cells(1, 6) And Dic.Exists(DL(i, 2)) Then
        j = j + 1
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    End If
và câu lệnh sau khác nhau kiểu gì nhỉ?
PHP:
If DL(i, 2) = Cells(1, 6) And Not Dic.Exists(DL(i, 2)) Then
        j = j + 1
        Dic.Add DL(i, 1), j
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    End If
    If DL(i, 2) = Cells(1, 6) And Dic.Exists(DL(i, 2)) Then
        j = j + 1
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    End If
 
Upvote 0
ơ bỗng dưng hôm này đọc lại em lại thấy lúng túng ở đây như vậy 2 cầu lệnh
PHP:
If DL(i, 2) = Cells(1, 6) And Not Dic.Exists(DL(i, 2)) Then
        j = j + 1
        Dic.Add DL(i, 1), j
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    ElseIf DL(i, 2) = Cells(1, 6) And Dic.Exists(DL(i, 2)) Then
        j = j + 1
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    End If
và câu lệnh sau khác nhau kiểu gì nhỉ?
PHP:
If DL(i, 2) = Cells(1, 6) And Not Dic.Exists(DL(i, 2)) Then
        j = j + 1
        Dic.Add DL(i, 1), j
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    End If
    If DL(i, 2) = Cells(1, 6) And Dic.Exists(DL(i, 2)) Then
        j = j + 1
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    End If
2 cái IF khác nhau, đương nhiên là làm xong cái IF này sẽ đến cái IF kia
1 bộ IF.. ElseIF.. End IF thì khác, nó có sự loại trừ ---> Thỏa mản cái trên thì khỏi làm cái dưới và ngược lại
 
Upvote 0
Khác nhau chứ bạn, trong Code
PHP:
If DL(i, 2) = Cells(1, 6) And Not Dic.Exists(DL(i, 2)) Then
        j = j + 1
        Dic.Add DL(i, 1), j
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    ElseIf DL(i, 2) = Cells(1, 6) And Dic.Exists(DL(i, 2)) Then
        j = j + 1
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    End If
cú pháp này tương đương với lệnh If trong Excel tức là đã thuộc trường hợp trên thì làm sao mà xét tiếp được ElseIf nữa.

Trong khi đó:
PHP:
If DL(i, 2) = Cells(1, 6) And Not Dic.Exists(DL(i, 2)) Then
        j = j + 1
        Dic.Add DL(i, 1), j
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    End If
    If DL(i, 2) = Cells(1, 6) And Dic.Exists(DL(i, 2)) Then
        j = j + 1
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    End If
Hai thằng If này độc lập, chẳng liên quan gì đến nhau, thằng If đầu tiên đã làm rồi thì đến If dưới thẩm định lại 1 lần nữa
 
Lần chỉnh sửa cuối:
Upvote 0
Hai thằng If này độc lập, chẳng liên quan gì đến nhau, thằng If đầu tiên đã làm rồi thì đến If dưới thẩm định lại 1 lần nữa

Bạn giải thích bạn có xem lại code bạn post không vậy? Đọc 1 chút tẩu quả nhập ma luôn đó, nói chung bạn giả thích thì Ok rồi nhưng 2 đoạn code bạn post chéo gheo hà
 
Upvote 0
Chiều nay tôi làm thử mấy bài trước sưu tầm từ diễn đàn về làm, đến bài này thì 2 Code sau có 1 cái chạy đúng, cái sau không chạy (lỗi). Bản thân tôi thấy rằng nó giống nhau mà không giải thích được

Code chạy đúng kết quả

PHP:
Sub Loc()
    Dim DL, i, KQ(), j
    DL = Range([A3], [A50000].End(xlUp)).Resize(, 2).Value
    ReDim KQ(1 To UBound(DL), 1 To 4)
        For i = 2 To UBound(DL)
            If DL(i, 2) > 0 Then
                If DL(i, 2) <> DL(i - 1, 2) Then
                j = j + 1
                KQ(j, 1) = DL(i, 1)
                KQ(j, 3) = 1
                KQ(j, 4) = DL(i, 2)
                KQ(j, 2) = DL(i, 1)
                ElseIf DL(i, 2) = DL(i - 1, 2) And DL(i, 2) <> DL(i + 1, 2) Then
                KQ(j, 2) = DL(i, 1)
                KQ(j, 3) = KQ(j, 3) + 1
                ElseIf DL(i, 2) = DL(i - 1, 2) And DL(i, 2) = DL(i + 1, 2) Then
                KQ(j, 3) = KQ(j, 3) + 1
                End If
            End If
        Next
        Range("C:F").ClearContents
        [C4].Resize(j, 4).Value = KQ
End Sub

------------
Trong khi Code sau thì lại lỗi (dù chỉ thay mỗi khai báo mảng DL thôi)
PHP:
Sub Loc()
    Dim DL, i, KQ(), j
    DL = Range([A3], [B50000].End(xlUp)).Value
    ReDim KQ(1 To UBound(DL), 1 To 4)
        For i = 2 To UBound(DL)
            If DL(i, 2) > 0 Then
                If DL(i, 2) <> DL(i - 1, 2) Then
                j = j + 1
                KQ(j, 1) = DL(i, 1)
                KQ(j, 3) = 1
                KQ(j, 4) = DL(i, 2)
                KQ(j, 2) = DL(i, 1)
                ElseIf DL(i, 2) = DL(i - 1, 2) And DL(i, 2) <> DL(i + 1, 2) Then
                KQ(j, 2) = DL(i, 1)
                KQ(j, 3) = KQ(j, 3) + 1
                ElseIf DL(i, 2) = DL(i - 1, 2) And DL(i, 2) = DL(i + 1, 2) Then
                KQ(j, 3) = KQ(j, 3) + 1
                End If
            End If
        Next
        Range("C:F").ClearContents
        [C4].Resize(j, 4).Value = KQ
End Sub
 

File đính kèm

  • Bai toan loc.xlsx
    38.4 KB · Đọc: 42
Upvote 0
Chiều nay tôi làm thử mấy bài trước sưu tầm từ diễn đàn về làm, đến bài này thì 2 Code sau có 1 cái chạy đúng, cái sau không chạy (lỗi). Bản thân tôi thấy rằng nó giống nhau mà không giải thích được

Code chạy đúng kết quả

PHP:
Sub Loc()
    Dim DL, i, KQ(), j
    DL = Range([A3], [A50000].End(xlUp)).Resize(, 2).Value
    ReDim KQ(1 To UBound(DL), 1 To 4)
        For i = 2 To UBound(DL)
            If DL(i, 2) > 0 Then
                If DL(i, 2) <> DL(i - 1, 2) Then
                j = j + 1
                KQ(j, 1) = DL(i, 1)
                KQ(j, 3) = 1
                KQ(j, 4) = DL(i, 2)
                KQ(j, 2) = DL(i, 1)
                ElseIf DL(i, 2) = DL(i - 1, 2) And DL(i, 2) <> DL(i + 1, 2) Then
                KQ(j, 2) = DL(i, 1)
                KQ(j, 3) = KQ(j, 3) + 1
                ElseIf DL(i, 2) = DL(i - 1, 2) And DL(i, 2) = DL(i + 1, 2) Then
                KQ(j, 3) = KQ(j, 3) + 1
                End If
            End If
        Next
        Range("C:F").ClearContents
        [C4].Resize(j, 4).Value = KQ
End Sub

------------
Trong khi Code sau thì lại lỗi (dù chỉ thay mỗi khai báo mảng DL thôi)
PHP:
Sub Loc()
    Dim DL, i, KQ(), j
    DL = Range([A3], [B50000].End(xlUp)).Value
    ReDim KQ(1 To UBound(DL), 1 To 4)
        For i = 2 To UBound(DL)
            If DL(i, 2) > 0 Then
                If DL(i, 2) <> DL(i - 1, 2) Then
                j = j + 1
                KQ(j, 1) = DL(i, 1)
                KQ(j, 3) = 1
                KQ(j, 4) = DL(i, 2)
                KQ(j, 2) = DL(i, 1)
                ElseIf DL(i, 2) = DL(i - 1, 2) And DL(i, 2) <> DL(i + 1, 2) Then
                KQ(j, 2) = DL(i, 1)
                KQ(j, 3) = KQ(j, 3) + 1
                ElseIf DL(i, 2) = DL(i - 1, 2) And DL(i, 2) = DL(i + 1, 2) Then
                KQ(j, 3) = KQ(j, 3) + 1
                End If
            End If
        Next
        Range("C:F").ClearContents
        [C4].Resize(j, 4).Value = KQ
End Sub


DL = Range([A3], [B50000].End(xlUp)).Value

DL = Range([A3], [A50000].End(xlUp)).Resize(, 2).Value

Có thể nói giống nhau và cũng có thể nói khác nhau.

Lý do giống nhau: Nếu hàng cuối cùng có giá trị của cột A bằng với hàng có giá trị ở cột B

Lý do sai: Nếu A có 10 dòng, B có 5 dòng thì với Range([A3], [B50000].End(xlUp)).Value chỉ là khối ô A3:B8 mà thôi.

Nhưng với Range([A3], [A50000].End(xlUp)).Resize(, 2).Value thì sẽ là A3:B13

Bạn thử nghiệm xem tại sao nhé!
 
Upvote 0
Chiều nay tôi làm thử mấy bài trước sưu tầm từ diễn đàn về làm, đến bài này thì 2 Code sau có 1 cái chạy đúng, cái sau không chạy (lỗi). Bản thân tôi thấy rằng nó giống nhau mà không giải thích được

Code chạy đúng kết quả

PHP:
Sub Loc()
    Dim DL, i, KQ(), j
    DL = Range([A3], [A50000].End(xlUp)).Resize(, 2).Value
    ReDim KQ(1 To UBound(DL), 1 To 4)
        For i = 2 To UBound(DL)
            If DL(i, 2) > 0 Then
                If DL(i, 2) <> DL(i - 1, 2) Then
                j = j + 1
                KQ(j, 1) = DL(i, 1)
                KQ(j, 3) = 1
                KQ(j, 4) = DL(i, 2)
                KQ(j, 2) = DL(i, 1)
                ElseIf DL(i, 2) = DL(i - 1, 2) And DL(i, 2) <> DL(i + 1, 2) Then
                KQ(j, 2) = DL(i, 1)
                KQ(j, 3) = KQ(j, 3) + 1
                ElseIf DL(i, 2) = DL(i - 1, 2) And DL(i, 2) = DL(i + 1, 2) Then
                KQ(j, 3) = KQ(j, 3) + 1
                End If
            End If
        Next
        Range("C:F").ClearContents
        [C4].Resize(j, 4).Value = KQ
End Sub

------------
Trong khi Code sau thì lại lỗi (dù chỉ thay mỗi khai báo mảng DL thôi)
PHP:
Sub Loc()
    Dim DL, i, KQ(), j
    DL = Range([A3], [B50000].End(xlUp)).Value
    ReDim KQ(1 To UBound(DL), 1 To 4)
        For i = 2 To UBound(DL)
            If DL(i, 2) > 0 Then
                If DL(i, 2) <> DL(i - 1, 2) Then
                j = j + 1
                KQ(j, 1) = DL(i, 1)
                KQ(j, 3) = 1
                KQ(j, 4) = DL(i, 2)
                KQ(j, 2) = DL(i, 1)
                ElseIf DL(i, 2) = DL(i - 1, 2) And DL(i, 2) <> DL(i + 1, 2) Then
                KQ(j, 2) = DL(i, 1)
                KQ(j, 3) = KQ(j, 3) + 1
                ElseIf DL(i, 2) = DL(i - 1, 2) And DL(i, 2) = DL(i + 1, 2) Then
                KQ(j, 3) = KQ(j, 3) + 1
                End If
            End If
        Next
        Range("C:F").ClearContents
        [C4].Resize(j, 4).Value = KQ
End Sub
- Thứ nhất: Bạn For i = 2 to UBound(DL) nhưng lại có đoạn viết DL(i, 2) <> DL(i + 1, 2) ---> Vượt quá giới hạn cho phép ---> Lý ra phải For i = 2 to UBound(DL) -1
- Thứ hai: [A50000].End(xlUp) khác với B50000].End(xlUp) vì dữ liệu của bạn có "rác" ở bên dưới ---> Hãy clear hết dữ liệu từ dòng 279 đến dòng cuối cùng rồi thử lại code
 
Upvote 0
Thực ra, tôi đoán biết được Code thứ 2 bị lỗi do không thực hiện được i+1 trong đoạn DL(i, 2) <> DL(i + 1, 2) như thày vừa nêu, nhưng đúng là không biết rác ở dưới cột A nó còn nên cứ hỏi tại sao thằng Code 1 lại chạy ngon.

Nếu bài này không vướng rác thì mình xử lý cái thằng DL(i + 1, 2) thế nào? hay là chọn thừa ra 1 hàng hả thày?
 
Upvote 0
Thực ra, tôi đoán biết được Code thứ 2 bị lỗi do không thực hiện được i+1 trong đoạn DL(i, 2) <> DL(i + 1, 2) như thày vừa nêu, nhưng đúng là không biết rác ở dưới cột A nó còn nên cứ hỏi tại sao thằng Code 1 lại chạy ngon.

Nếu bài này không vướng rác thì mình xử lý cái thằng DL(i + 1, 2) thế nào? hay là chọn thừa ra 1 hàng hả thày?
Cũng có thể thêm đoạn On Error Resume Next lên đầu code (code cũ để nguyên) ---> Như vậy khi gặp lỗi nó tự vượt qua luôn
Ẹc... Ẹc..
 
Upvote 0
Mình làm theo dạng gán vào ArrKQ tới đâu thì add sh liền và redim.
Ndu test giúp. Cám ơn!
Vừa test xong dữ liệu 40000 dòng ---> Kết quả 2.5 giây
Ẹc... Ẹc... nhanh thật
Nhưng... cái này còn nhanh hơn nè:
PHP:
Sub Tonghop()
  Dim sArray, SrcRng As Range, i As Long, T As Double, WshName As String, keyArr
  Dim Dic As Object, Tmp As String
  T = Timer
  On Error Resume Next
  Application.ScreenUpdating = False
  Set Dic = CreateObject("Scripting.Dictionary")
  With Sheets("Data")
    .Range("K1").Value = .Range("B4").Value
    Set SrcRng = .Range("A4:E50000")
    sArray = SrcRng.Value
    For i = 2 To UBound(sArray, 1)
      If Len(CStr(sArray(i, 2))) Then
        Tmp = CStr(sArray(i, 2))
        If Not Dic.Exists(Tmp) Then Dic.Add Tmp, Nothing
      End If
    Next
    If Dic.Count Then
      keyArr = Dic.Keys
      For i = 1 To Dic.Count
        WshName = CStr(keyArr(i - 1))
        If isValidWshName(WshName) Then
          If Not SheetExist(WshName) Then
            Sheets.Add(After:=Sheets(Sheets.Count)).Name = WshName
            .Range("K2") = WshName
          End If
        End If
        Sheets(WshName).UsedRange.ClearContents
        SrcRng.AdvancedFilter 2, .Range("K1:K2"), Sheets(WshName).Range("A1")
      Next
    End If
    .[K1:K2].Clear
    Application.ScreenUpdating = True
    MsgBox Timer - T
  End With
End Sub
Advanced Filter cho kết quả trong vòng 1 giây
 
Upvote 0
Web KT

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

Back
Top Bottom