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

  • Thread starter Thread starter viehoai
  • Ngày gửi Ngày gửi
Liên hệ QC

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

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ị
 
Chèn mãng vào mãngGiả sửa tôi có 2 mãng như file đính kèmKính nhờ các anh chi thuật toán (hoặc có code luôn càng tốt) để chèn 1 mãng thứ 2 vào mãng thứ nhất theo 1 điều kiệnXin cảm ơn các anh chị
Có phải là gặp cột A có chữ "a" thì gán mảng 2 vào.
Dễ mà, VietHoai tự làm thử.
PHP:
Sub TaoKQ()
Dim i&, j&, k&, s&
Dim Arr01, Arr02, ArrKQ
Arr01 = Range("A2:D10").Value
Arr02 = Range("H2:K6").Value
ReDim ArrKQ(1 To 5000, 1 To UBound(Arr01, 2))
For i = 1 To UBound(Arr01, 1)
  If Arr01(i, 1) <> "a" Then
    s = s + 1
    For k = 1 To UBound(Arr01, 2)
      ArrKQ(s, k) = Arr01(i, k)
    Next k
  Else
    For j = 1 To UBound(Arr02, 1)
      s = s + 1
      For k = 1 To UBound(Arr01, 2)
        ArrKQ(s, k) = Arr02(j, k)
      Next k
    Next j
  End If
Next i
Range("F18").Resize(s, k - 1) = ArrKQ
Erase Arr01, Arr02, ArrKQ
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Sao kg chèn vào Arr (KQ) 1 lần sau đó gán xuống sh.
PHP:
Sub Chendong2()
Dim DL, i As Long, s&
Dim KQ
DL = Range([A1], [A65000].End(xlUp)).Value
ReDim KQ(1 To UBound(DL, 1) * 2, 1 To 1)
For i = 1 To UBound(DL, 1)
  s = s + 1
  KQ(s, 1) = DL(i, 1)
  If DL(i, 1) <> "" Then
    s = s + 1
    KQ(s, 1) = ""
  End If
Next
Cells(1, 1).Resize(s) = KQ
End Sub
Ah... ha!
Nếu vùng DL có công thức thì cách này không xong à nghen ---> Dù ta thay .Value thành .Formula cũng... tèo...
Nhớ rằng nếu chèn dòng bằng tay thì các tham chiếu trong công thức tự động "dịch chuyển" theo ---> Làm sao ta làm được điều này trong mảng?
Nói chung, chỉ áp dụng cách này với dữ liệu thô
Ẹc... Ẹc...
 
Upvote 0
Ah... ha!
Nếu vùng DL có công thức thì cách này không xong à nghen ---> Dù ta thay .Value thành .Formula cũng... tèo...
Nhớ rằng nếu chèn dòng bằng tay thì các tham chiếu trong công thức tự động "dịch chuyển" theo ---> Làm sao ta làm được điều này trong mảng?
Nói chung, chỉ áp dụng cách này với dữ liệu thô
Ẹc... Ẹc...

Cách làm của bác Thu Nghi rất hay về mặt thuật toán, sáng tạo nhưng kết quả chỉ đúng khi áp dụng với dữ liệu thô vùng làm việc chỉ là một cột duy nhất (cột A).
 
Upvote 0
Cách làm của bác Thu Nghi rất hay về mặt thuật toán, sáng tạo nhưng kết quả chỉ đúng khi áp dụng với dữ liệu thô vùng làm việc chỉ là một cột duy nhất (cột A).
Công thức như NDU thì xem lại. Còn việc 1 hay > 1 cột cũng vậy thôi.
 
Upvote 0
1.
Có phải là gặp cột A có chữ "a" thì gán mảng 2 vào.
Dễ mà, VietHoai tự làm thử.
PHP:
Sub TaoKQ()
Dim i&, j&, k&, s&
Dim Arr01, Arr02, ArrKQ
Arr01 = Range("A2:D10").Value
Arr02 = Range("H2:K6").Value
ReDim ArrKQ(1 To 5000, 1 To UBound(Arr01, 2))
For i = 1 To UBound(Arr01, 1)
  If Arr01(i, 1) <> "a" Then
    s = s + 1
    For k = 1 To UBound(Arr01, 2)
      ArrKQ(s, k) = Arr01(i, k)
    Next k
  Else
    For j = 1 To UBound(Arr02, 1)
      s = s + 1
      For k = 1 To UBound(Arr01, 2)
        ArrKQ(s, k) = Arr02(j, k)
      Next k
    Next j
  End If
Next i
Range("F18").Resize(s, k - 1) = ArrKQ
Erase Arr01, Arr02, ArrKQ
End Sub
Tôi muốn mãng ArrKQ trở về kích thước của nó tôi dùng
PHP:
ReDim Preserve ArrKQ(1 To s, 1 To 5)
Vì sao nó báo lỗi nhỉ
2. Xin các anh chị giúp đỡ hàm để nối các mãng
Ví dụ tôi có các mãng Arr01, Arr02, Arr03 ...Arr(n) có cùng kích thước ngang. Bây giờ tôi cần hàm cho kết quả là mãng ArrKQ là nối tất cả các mãng đó thành 1 mãng.
Bây giờ tôi áp dụng 3 mãng thì chỉ cần dùng: Ví dụ hàm ArrKQ(Arr01, Arr02, Arr03)
Xin cảm ơn các anh chị
 
Lần chỉnh sửa cuối:
Upvote 0
Xin các anh chị giúp đỡ hàm để nối các mãng
Ví dụ tôi có các mãng Arr01, Arr02, Arr03 ...Arr(n) có cùng kích thước ngang. Bây giờ tôi cần hàm cho kết quả là mãng ArrKQ là nối tất cả các mãng đó thành 1 mãng.
Bây giờ tôi áp dụng 3 mãng thì chỉ cần dùng: Ví dụ hàm ArrKQ(Arr01, Arr02, Arr03)
Xin cảm ơn các anh chị
Hiện tại thì tôi chưa biết có cách nào ngoài cách for từng mảng và gán vào ArrKQ
Lúc đó phải Redim ArrKQ(1 to ubound(Arr01)+ ... +ubound(Arr_n),1 to ubound(Arr01,2))
Thấy có cú pháp CombineArray cũng phải như vậy.
 
Upvote 0
Hiện tại thì tôi chưa biết có cách nào ngoài cách for từng mảng và gán vào ArrKQ
Lúc đó phải Redim ArrKQ(1 to ubound(Arr01)+ ... +ubound(Arr_n),1 to ubound(Arr01,2))
Thấy có cú pháp CombineArray cũng phải như vậy.
Nếu xác định được số mãng thì đơn giản rồi anh à, vấn đề số mãng chưa biết mới là khó đối với em
 
Upvote 0
1.
Tôi muốn mãng ArrKQ trở về kích thước của nó tôi dùng
PHP:
ReDim Preserve ArrKQ(1 To s, 1 To 5)
Vì sao nó báo lỗi nhỉ
2. Xin các anh chị giúp đỡ hàm để nối các mãng
Ví dụ tôi có các mãng Arr01, Arr02, Arr03 ...Arr(n) có cùng kích thước ngang. Bây giờ tôi cần hàm cho kết quả là mãng ArrKQ là nối tất cả các mãng đó thành 1 mãng.
Bây giờ tôi áp dụng 3 mãng thì chỉ cần dùng: Ví dụ hàm ArrKQ(Arr01, Arr02, Arr03)
Xin cảm ơn các anh chị
ReDim Preserve ArrKQ(1 To s, 1 To 5)
Híc, cái thằng ReDim Preserve không cho chơi kiểu đó đâu, nó hổng cho ReDim Preserve theo chiều thứ 1 đâu
Thí dụ:
ReDim Preserve ArrKQ(1 To 5, 1 To s)
thì nó hổng cự nự bạn đâu
Tôi muốn mãng ArrKQ trở về kích thước của nó tôi dùng
Trong bài của bạn có thể khai báo chính xác kích thước mảng ArKQ như sau
SoA = Application.WorksheetFunction.CountIf([A2:A10], "a")
ReDim ArrKQ(1 To SoA * UBound(Arr02) + UBound(Arr01) - SoA, 1 To UBound(Arr01, 2))
Còn câu 2 ....mình hổng hiểu
Thân
Híc
 
Lần chỉnh sửa cuối:
Upvote 1
Híc, cái thằng ReDim Preserve không cho chơi kiểu đó đâu, nó hổng cho ReDim Preserve theo chiều thứ 1 đâuThí dụ:thì nó hổng cự nự bạn đâuTrong bài của bạn có thể khai báo chính xác kích thước mảng ArKQ như sauCòn câu 2 ....mình hổng hiểuThânHíc
Cảm ơn anh rất nhiều
1. Câu 2 ý em cần 1 hàm chung để nối các mãng với nhau theo thứ tự khai báoVí dụ: - Khi em cần nối 3 mãng thì em sử dụng hàm: ArrKQ(Arr01, Arr02, Arr03)
- Khi em cần nối 4 mãng thì em sử dụng hàm: ArrKQ(Arr01, Arr02, Arr03, Arr04) v.v.. (Nối với nhau theo phương dọc, phương ngang các mãng Arr01, Arr02, Arr03,Arr03 ... có cùng kích thước.
2. Xin các anh chị xem 2 file áp dụng code của anh ThuNghi có sử dụng thêm phép tính 1 file bị lỗi trong khi file khác thì khôngVì sao?
Xin cảm ơn các anh chị
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Không hiểu nguyên nhân tại sao Code báo lỗi ở dòng Dic.Add DL(i, 2), j

Tôi đang định thực hành, ôn lại những bài cơ bản ban đầu về Dictionary làm thử bài toán trích lọc doanh số cho vay theo từng Công ty, nhưng không hiểu tại sao Code lại báo lỗi màu vàng ở đoạn Dic.Add DL(i, 2), j, xin được chỉ giúp nguyên nhân.

PHP:
Sub Loc()
Dim DL(), KQ(), i As Long, j As Long
Dongcuoi = [C65000].End(xlUp).Row
DL = Range("A2:C" & Dongcuoi).Value
Set Dic = CreateObject("Scripting.Dictionayr")
ReDim KQ(1 To UBound(DL, 1), 1 To 3)
For i = 1 To UBound(DL, 1)
    If DL(i, 2) = Cells(1, 6) And Not Dic.Exists(DL(i, 1)) Then
        j = j + 1
        Dic.Add DL(i, 2), 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, 1)) Then
        j = j + 1
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    End If
Next
    [E2].Resize(j, 3).Value = KQ
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Bạn sai lỗi là do một mặt bạn check xem key có tồn tại không thì bạn check DL(i,1) trong khi bạn lại add key là DL(i,2) dẫn đến bị trùng key khi add
 
Upvote 0
Tôi đang định thực hành, ôn lại những bài cơ bản ban đầu về Dictionary làm thử bài toán trích lọc doanh số cho vay theo từng Công ty, nhưng không hiểu tại sao Code lại báo lỗi màu vàng ở đoạn Dic.Add DL(i, 2), j, xin được chỉ giúp nguyên nhân.

PHP:
Sub Loc()
Dim DL(), KQ(), i As Long, j As Long
Dongcuoi = [C65000].End(xlUp).Row
DL = Range("A2:C" & Dongcuoi).Value
Set Dic = CreateObject("Scripting.Dictionayr")
ReDim KQ(1 To UBound(DL, 1), 1 To 3)
For i = 1 To UBound(DL, 1)
    If DL(i, 2) = Cells(1, 6) And Not Dic.Exists(DL(i, 1)) Then
        j = j + 1
        Dic.Add DL(i, 2), 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, 1)) Then
        j = j + 1
        KQ(j, 1) = DL(i, 1)
        KQ(j, 2) = DL(i, 2)
        KQ(j, 3) = DL(i, 3)
    End If
Next
    [E2].Resize(j, 3).Value = KQ
End Sub
Bạn xem chổ này
Mã:
If DL(i, 2) = Cells(1, 6) And Not Dic.Exists([COLOR=#ff0000][B]DL(i, 1)[/B][/COLOR]) Then
        j = j + 1
        Dic.Add [COLOR=#ff0000][B]DL(i, 2)[/B][/COLOR], j
Chổ màu đỏ ấy ---> Chẳng ăn nhập gì nhau cả ---> Đ/k tồn tại là DL(i, 1) mà khi Add lại Add DL(i, 2)
 
Upvote 0
Tôi đã sửa thành:

PHP:
Sub Loc()
Dim DL(), KQ(), i As Long, j As Long
Dongcuoi = [C65000].End(xlUp).Row
DL = Range("A2:C" & Dongcuoi).Value
Set Dic = CreateObject("Scripting.Dictionary")
ReDim KQ(1 To UBound(DL, 1), 1 To 3)
For i = 1 To UBound(DL, 1)
    If DL(i, 2) = Cells(1, 6) And Not Dic.Exists(DL(i, 2)) Then
        j = j + 1
        Dic.Add DL(i, 2), 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
Next
    [E2].Resize(j, 3).Value = KQ
End Sub

Kết quả: Chạy ra kết quả thì dòng thứ nhất sao nó lặp 2 lần.
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi sửa được rồi thày ah, cảm ơn thày nhiều

PHP:
Sub Loc()
Dim DL(), KQ(), i As Long, j As Long
Dongcuoi = [C65000].End(xlUp).Row
DL = Range("A2:C" & Dongcuoi).Value
Set Dic = CreateObject("Scripting.Dictionary")
ReDim KQ(1 To UBound(DL, 1), 1 To 3)
For i = 1 To UBound(DL, 1)
    If DL(i, 2) = Cells(1, 6) And Not Dic.Exists(DL(i, 2)) Then
        j = j + 1
        Dic.Add DL(i, 2), 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
Next
    [E2].Resize(j, 3).Value = KQ
End Sub
Code mới này không lỗi gì cả! Có điều chẳng hiểu bạn muốn làm gì với code mới này???
Còn code cũ thì sai chữ "Dictionary" (bạn ghi là Dictionayr)
----------------
Kết quả: Chạy ra kết quả thì dòng thứ nhất sao nó lặp 2 lần.
- IF đầu tiên (điều kiện không tồn tại) --> Add vào
- Tiếp cái IF thứ 2 (điều kiện tồn tại) ---> Add vào tiếp
Thế là trùng lặp 2 lần rồi
Hỏi lại: Bạn muốn làm điều gì với file này?
- Lọc với điều kiện = Công ty A chăng?---> Thế thì cần gì đến Dictionary?
- Cộng dồn theo điều kiện Công ty A chăng? ---> Thế thì trong code của bạn không có chổ nào cộng dồn cả?
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi đã sửa thành:

PHP:
Sub Loc()
Dim DL(), KQ(), i As Long, j As Long
Dongcuoi = [C65000].End(xlUp).Row
DL = Range("A2:C" & Dongcuoi).Value
Set Dic = CreateObject("Scripting.Dictionary")
ReDim KQ(1 To UBound(DL, 1), 1 To 3)
For i = 1 To UBound(DL, 1)
    If DL(i, 2) = Cells(1, 6) And Not Dic.Exists(DL(i, 2)) Then
        j = j + 1
        Dic.Add DL(i, 2), 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
Next
    [E2].Resize(j, 3).Value = KQ
End Sub

Kết quả: Chạy ra kết quả thì dòng thứ nhất sao nó lặp 2 lần.

Lặp hai lần vì bạn If hai lần, giả sử key chưa tồn tại, vào vòng If thứ nhất sẽ add key đó và nó sẽ trở thành key tồn tại, thế là làm tiếp vòng If thứ hai dẫn đến lặp. Đáng ra bạn phải sửa lại rằng
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
 
Upvote 0
Tức là tôi trích lọc những dòng mà cột B xuất hiện riêng Công ty A thôi (bảng DL tổng hợp ban đầu bao gồm rất nhiều Công ty). Tuy vậy , thuật toán chưa đúng dẫn đến dòng đầu tiên bị lặp trùng 2 lần, tôi đang tìm nguyên nhân và sửa nó
(Xin gửi file cho mọi người dễ hình dung)
-----------
Cảm ơn thày, lúc vừa gửi lên thì trước đó thày đã giúp cho rồi ah. Trong lúc nghĩ nhờ thày giúp, tôi cũng đã phát hiện được nguyên nhân sai ra khi i=1 dòng thứ nhất thỏa mãn cả 2 lệnh If mà không nghĩ ra được ElseIf.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
- IF đầu tiên (điều kiện không tồn tại) --> Add vào
- Tiếp cái IF thứ 2 (điều kiện tồn tại) ---> Add vào tiếp
Thế là trùng lặp 2 lần rồi
Hỏi lại: Bạn muốn làm điều gì với file này?
- Lọc với điều kiện = Công ty A chăng?---> Thế thì cần gì đến Dictionary?
- Cộng dồn theo điều kiện Công ty A chăng? ---> Thế thì trong code của bạn không có chổ nào cộng dồn cả?

Ý định của tôi là lọc chứ không cộng dồn thày ah, nhưng If thứ 2 mình có cho nó Add đâu nhỉ?, nó chỉ sai ở chỗ vì nó khoái (thỏa mãn điều kiện) cả 2 anh If tự nhiên j ở câu lệnh thứ 2 lại tiếp tục được tăng thêm 1 đơn vị (1+1=2), tức là riêng dòng đầu được 2 thằng j liền j=1 và j=2?? >> 2 dòng trung nhau thôi chứ thày
 
Lần chỉnh sửa cuối:
Upvote 0
Tức là tôi trích lọc những dòng mà cột B xuất hiện riêng Công ty A thôi (bảng DL tổng hợp ban đầu bao gồm rất nhiều Công ty). Tuy vậy , thuật toán chưa đúng dẫn đến dòng đầu tiên bị lặp trùng 2 lần, tôi đang tìm nguyên nhân và sửa nó
(Xin gửi file cho mọi người dễ hình dung)
-----------
Cảm ơn thày, lúc vừa gửi lên thì trước đó thày đã giúp cho rồi ah. Trong lúc nghĩ nhờ thày giúp, tôi cũng đã phát hiện được nguyên nhân sai ra khi i=1 dòng thứ nhất thỏa mãn cả 2 lệnh If mà không nghĩ ra được ElseIf.
Tức là tìm trong cột B, cái nào = "Công ty A" thì lấy nguyên dòng cho vào mảng KQ, đúng không? Vậy cứ duyệt mảng bình thường, bài toán này chẳng có chổ nào liên quan đến Dictionary cả
Vầy là đủ:
PHP:
Sub Loc()
  Dim DL(), KQ(), i As Long, j As Long
  DL = Range([A2], [C65000].End(xlUp)).Value
  ReDim KQ(1 To UBound(DL, 1), 1 To 3)
  For i = 1 To UBound(DL, 1)
    If DL(i, 2) = Cells(1, 6) Then
      j = j + 1
      KQ(j, 1) = DL(i, 1)
      KQ(j, 2) = DL(i, 2)
      KQ(j, 3) = DL(i, 3)
    End If
  Next
  [E2].Resize(j, 3).Value = KQ
End Sub
 
Upvote 0
Mấy hôm nọ học Dictionary tốc độ nhanh quá (so với khả năng tiếp thu của bản thân) nên chưa kịp nhìn lại, hôm nay rỗi ngồi ôn lại để hình dung ra toàn bộ các bài cơ bản về Dic hôm nọ được thày Ndu hướng dẫn.

Vì đang muốn vận dụng Dic, thay đổi các dạng bài bài toán xoay quanh đến lính vực TỒN TẠI để vận dụng Dic nên không còn đủ tỉnh táo để chợt nhớ ra cách trên của thày hay hơn (máy móc quá)
 
Lần chỉnh sửa cuối:
Upvote 0
Tại sao kết quả tổng hợp sao không cộng thêm những dòng dưới nhỉ

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 đỡ

Tonghoptheongaythang.png


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
 
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 đỡ
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

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

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
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:
        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
Mình cũng test lại, việc Clear cũng mất nhiều thời gian khi WB đã có sh tồn tại.
Thử dùng Arr 1 chiều thay thế ArrBP thì thấy tốc độ code NDU và mình cũng thời gian gần như nhau.
PHP:
Sub TonghopArr()
  Dim sArray, subArr(), Arr(), i 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")
  Application.ScreenUpdating = False
  With Sheets("Data")
    sArray = .Range("A5:E60000").Value
    Title = .Range("A4:E4").Value
  End With
  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
        ReDim Preserve ArrBP(1 To n)
      End If
      nR = Dic.Item(Tmp)
      If Len(ArrBP(nR)) Then
        ArrBP(nR) = ArrBP(nR) & vbBack & i
      Else
        ArrBP(nR) = i
      End If
    End If
  Next
 For i = 1 To UBound(ArrBP)
    nR = 0
    Tmp = CStr(ArrBP(i))
    aSplit = Split(Tmp, vbBack)
    ReDim subArr(1 To UBound(aSplit) + 1, 1 To UBound(sArray, 2))
    For j = 0 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(subArr(1, 2))
    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.ClearContents
      .Range("A1").Resize(, UBound(sArray, 2)).Value = Title
      .Range("A2").Resize(UBound(aSplit) + 1, UBound(sArray, 2)) = subArr
    End With
  Next i
  Application.ScreenUpdating = True
MsgBox Timer - T
End Sub
Cám ơn NDU. Đang tính vận dụng để làm tạo sổ cái (kế toán) liên tục. Còn vài vấn đề là số sh > 256 hay chạy tạo khoảng 50 sh thì nên save lại nữa.
Chỉ có điều sao code mình viết dài quá, Bác Cò và Bác Mỹ cứ chê hoài.
 
Upvote 0
Cụ thể hơn 1 chút đi, sai file nào và tiêu chí là sao ở file ghepmang. Chưa hiểu yêu cầu.
Trong file GhepMang bị lỗi khi dòng lệnh trong đoạn
PHP:
If k = 4 Then
    ArrKQ(s, k) = "=" & ArrV(j, k)
Else
    ArrKQ(s, k) = ArrV(j, k)
End If
Có thêm dấu "=", nếu bỏ nó thì không lỗi. Nghĩa là em muốn phần tử mãng gán với phép tính
 
Upvote 0
Trong file GhepMang bị lỗi khi dòng lệnh trong đoạn
PHP:
If k = 4 Then
    ArrKQ(s, k) = "=" & ArrV(j, k)
Else
    ArrKQ(s, k) = ArrV(j, k)
End If
Có thêm dấu "=", nếu bỏ nó thì không lỗi. Nghĩa là em muốn phần tử mãng gán với phép tính
Hiểu rồi,
- if tìm cột D lấy 4 số lẻ cuối > 179 hay =0 thì giữ nguyên.
- If not thì lấy cột E tham chiếu với sh Data và lấy các cột còn lại.
Tôi để hay bỏ dấu = thì code vẫn chạy bình thường mà.
Đang tìm cách tối hưu code trên theo hướng Arr toàn bộ.
 
Upvote 0
Hiểu rồi,
- if tìm cột D lấy 4 số lẻ cuối > 179 hay =0 thì giữ nguyên.
- If not thì lấy cột E tham chiếu với sh Data và lấy các cột còn lại.
Tôi để hay bỏ dấu = thì code vẫn chạy bình thường mà.
Đang tìm cách tối hưu code trên theo hướng Arr toàn bộ.
Anh thử thêm "=" và bỏ nó rồi test xem file này thử giúp em nhé
 

File đính kèm

Upvote 0
Hiểu rồi,
- if tìm cột D lấy 4 số lẻ cuối > 179 hay =0 thì giữ nguyên.
- If not thì lấy cột E tham chiếu với sh Data và lấy các cột còn lại.
Tôi để hay bỏ dấu = thì code vẫn chạy bình thường mà.
Đang tìm cách tối hưu code trên theo hướng Arr toàn bộ.
Dấu thập phân hệ thống "." và "," đã bị bao nhiêu lần, và đã giúp nhiều người rồi mà vẫn bị cái này lừa
Cảm ơn anh, bài viết này làm em mới để ý nó. Như thế này sẽ hết lỗi luôn
PHP:
ArrKQ(s, k) = "=" & Replace(ArrV(j, k) & "*" & KLdm, ",", ".")
Nhưng câu 2 bài #309 vẫn chưa được các anh chị giúp đỡ. Xin các anh chị giúp tiếp
 
Upvote 0
Dấu thập phân hệ thống "." và "," đã bị bao nhiêu lần, và đã giúp nhiều người rồi mà vẫn bị cái này lừa
Cảm ơn anh, bài viết này làm em mới để ý nó. Như thế này sẽ hết lỗi luôn
PHP:
ArrKQ(s, k) = "=" & Replace(ArrV(j, k) & "*" & KLdm, ",", ".")
Nhưng câu 2 bài #309 vẫn chưa được các anh chị giúp đỡ. Xin các anh chị giúp tiếp
Dùng thêm 1 for thế Find => nR.
PHP:
Sub TaoKQ2()
Dim i&, j&, k&, s&, nR&
Dim MyRange, ArrV, ArrKQ
Dim KLdm$
MyRange = Sheet1.Range("A1:E9").Value
ReDim ArrKQ(1 To 30, 1 To UBound(MyRange, 2))
For i = 1 To UBound(MyRange, 1)
  If Val(Right(MyRange(i, 5), 4)) > 179 Or Val(Right(MyRange(i, 5), 4)) = 0 Then
    s = s + 1
    For k = 1 To UBound(MyRange, 2)
      ArrKQ(s, k) = MyRange(i, k)
    Next k
  Else
    KLdm = MyRange(i, 5)
    ArrV = Sheet2.Range("A1:D1000").Value
    For j = 1 To UBound(ArrV, 1)
      If ArrV(j, 1) = KLdm Then
        nR = j + 1
        Exit For
      End If
    Next j
    For j = nR To UBound(ArrV, 1)
      If Len(ArrV(j, 1)) = 0 Then
        s = s + 1
        For k = 1 To 3
          ArrKQ(s, k) = ArrV(j, k)
          ArrKQ(s, 4) = "=" & ArrV(j, 4)
          ArrKQ(s, 5) = KLdm
        Next k
      End If
      If Len(ArrV(j, 1)) > 0 Then Exit For
    Next j
  End If
Next i
If s Then
  Sheet1.Range("A15").Resize(s, UBound(ArrKQ, 2)).Value = ArrKQ
End If
Erase MyRange, ArrV, ArrKQ
End Sub
Nếu Find nhiều đối tượng thì dùng Dic đẩ lấy dữ liệu của sh 2.
 
Upvote 0
Các bạn xem giùm tôi đoạn code này sai chỗ nào mà không thể chạy được(tôi đang bắt đầu học VBA, nếu thấy vấn đề đơn giản quá mong các bác đừng cuời nhé!)

PHP:
Sub btoan()
    Dim Vung, DL(), i As Long
    Set Vung = Range([A4], [G65000].End(xlUp)).Resize(, 8)
    DL = Vung.Value
    ReDim KQ(1 To UBound(DL, 1), 1 To 1)
        For i = 1 To UBound(DL, 1)
        If DL(i, 1) > 0 Then
            j = j + 1
        ElseIf DL(i, 3) <> "" Then
            m = Vung(i, 3).Row
            KQ(m, 1) = DL(m, 7) * DL(j, 6)
        End If
        [H4].Resize(m).Value = KQ
    Next
    
End Sub
 

File đính kèm

Upvote 0
Các bạn xem giùm tôi đoạn code này sai chỗ nào mà không thể chạy được(tôi đang bắt đầu học VBA, nếu thấy vấn đề đơn giản quá mong các bác đừng cuời nhé!)

PHP:
        For i = 1 To UBound(DL, 1)
        If DL(i, 1) > 0 Then
            j = j + 1
        ElseIf DL(i, 3) <> "" Then
            m = Vung(i, 3).Row
            KQ(m, 1) = DL(m, 7) * DL(j, 6)
        End If
        [H4].Resize(m).Value = KQ
Nếu if và elseif trên kg thỏa thì lấy m =? => [H4].Resize(m).Value = KQ kg gán dc.
Và bạn cũng nên nói cụ thể hơn là bạn cần gì. Nhìn file này thấy có vẻ quen, giống như của nick nào đó.
Sub bto1()
Dim KQ(), DL(), i As Long
DL = Range([A4], [G65000].End(xlUp)).Resize(, 8).Value
Dim kl As Double
ReDim KQ(1 To UBound(DL, 1), 1 To 1)
For i = 1 To UBound(DL, 1)
If DL(i, 1) > 0 Then
kl = DL(i, 6)
Else
If DL(i, 3) <> "" Then
KQ(i, 1) = DL(i, 7) * kl
End If
End If
Next
[H4].Resize(i - 1).Value = KQ
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Mình không biết bạn tính ra sau như bạn để đoạn code này [H4].Resize(m).Value = KQ
Ra ngoài vòng lặp là được
 
Upvote 0
Mẫu biểu bài này tôi tải về từ diễn đàn, ý tôi muốn điền công thức tại mỗi công việc cho cột H bằng (=) cột FxG, nghĩa là vật tư = thi công x định mức ấy mà.

Tôi xin gửi file hiển thị kết quả, mong được các bác chỉ cho.
 

File đính kèm

Upvote 0
Mẫu biểu bài này tôi tải về từ diễn đàn, ý tôi muốn điền công thức tại mỗi công việc cho cột H bằng (=) cột FxG, nghĩa là vật tư = thi công x định mức ấy mà.

Tôi xin gửi file hiển thị kết quả, mong được các bác chỉ cho.
Code tôi đã làm trong bài trước. Và có sửa lại là
Nếu dòng 18, cụ thể C18 ="" thì sao thỏa. Vậy tôi sửa lại code như sau:
PHP:
Sub bto1()
 Dim KQ(), DL(), i As Long
 DL = Range([A4], [G65000].End(xlUp)).Resize(, 8).Value
 Dim kl As Double
 ReDim KQ(1 To UBound(DL, 1), 1 To 1)
 For i = 1 To UBound(DL, 1)
  If DL(i, 1) > 0 Then
    kl = DL(i, 6)
  Else
    If DL(i, 7) <> "" Then
      KQ(i, 1) = DL(i, 7) * kl
    End If
  End If
 Next
 [J4].Resize(i - 1).Value = KQ
 End Sub
 
Upvote 0
Mẫu biểu bài này tôi tải về từ diễn đàn, ý tôi muốn điền công thức tại mỗi công việc cho cột H bằng (=) cột FxG, nghĩa là vật tư = thi công x định mức ấy mà.

Tôi xin gửi file hiển thị kết quả, mong được các bác chỉ cho.
Công thức cho cell H4:
PHP:
=IF(C4="","",LOOKUP(10^15,$F$4:$F4)*LOOKUP(10^15,$G$4:$G4))
Kéo fill xuống! Khỏi code kiết chi cho mệt
 
Upvote 0
Công thức nhìn choáng quá, tôi không hiểu cái này 10^15 là cái gì thế? phiền thày Ndu chỉ cho.
 
Upvote 0
Công thức nhìn choáng quá, tôi không hiểu cái này 10^15 là cái gì thế? phiền thày Ndu chỉ cho.
LOOKUP với giá trị tìm là số cực lớn (10^15) thì kết quả trả về sẽ là phần tử cuối cùng có giá trị trong mảng
Vậy thôi
 
Upvote 0
Chán quá, không hiểu sao mảng khó thế nhìn các bác trên diễn đàn làm ngon thế mà khi lao vào làm mới thấy khó thật, hôm nay sưu tầm các bài trên diễn đàn về làm nhưng sai nhiều quá.

Tôi lấy thử bài toán nhỏ:
- Cột I = Cột H x Cột G (Thành tiền = đơn giá x khối lượng định mức)
- Thành tiền mỗi công việc = VL+NC+MTC

Tôi viết Code như sau, trình độ còi quá không biết sai kiến thức cơ bản ở chỗ nào mà không biết

PHP:
Sub Ttoan()
    Dim Vung, DL(), i As Long, Nhom As Long, CongViec As Long, Tmp1, Tmp2
    dongcuoi = [G65000].End(xlUp).Row
    Set Vung = Range("A4:I" & dongcuoi)
    DL = Vung.Value
    Range("I4:I" & dongcuoi).ClearContents
    ReDim KQ(1 To UBound(DL, 1), 1 To 1)
    For i = UBound(DL, 1) To 1 Step -1
        Tmp1 = Tmp1 + DL(i, 9)
        If DL(i, 1) = "" And DL(i, 2) = "" Then
            Nhom = i
            KQ(Nhom, 1) = Tmp1
            Tmp2 = Tmp1 + Tmp2
            Tmp1 = 0
        ElseIf DL(i, 1) <> "" Then
            CongViec = i
            KQ(CongViec, 1) = Tmp2
            Tmp2 = 0
        ElseIf DL(i, 3) <> "" Then
            DL(i, 9) = DL(i, 7) * DL(i, 8)
        End If
    Next
    [I4].Resize(UBound(DL, 1)).Value = KQ
End Sub

Nhìn các anh nmhung49, trungvdb, bạn hoamattroicoi làm veo veo mà thấy thẹn quá
 

File đính kèm

Upvote 0
Chán quá, không hiểu sao mảng khó thế nhìn các bác trên diễn đàn làm ngon thế mà khi lao vào làm mới thấy khó thật, hôm nay sưu tầm các bài trên diễn đàn về làm nhưng sai nhiều quá.

Tôi lấy thử bài toán nhỏ:
- Cột I = Cột H x Cột G (Thành tiền = đơn giá x khối lượng định mức)
- Thành tiền mỗi công việc = VL+NC+MTC

Tôi viết Code như sau, trình độ còi quá không biết sai kiến thức cơ bản ở chỗ nào mà không biết

PHP:
Sub Ttoan()
    Dim Vung, DL(), i As Long, Nhom As Long, CongViec As Long, Tmp1, Tmp2
    dongcuoi = [G65000].End(xlUp).Row
    Set Vung = Range("A4:I" & dongcuoi)
    DL = Vung.Value
    Range("I4:I" & dongcuoi).ClearContents
    ReDim KQ(1 To UBound(DL, 1), 1 To 1)
    For i = UBound(DL, 1) To 1 Step -1
        Tmp1 = Tmp1 + DL(i, 9)
        If DL(i, 1) = "" And DL(i, 2) = "" Then
            Nhom = i
            KQ(Nhom, 1) = Tmp1
            Tmp2 = Tmp1 + Tmp2
            Tmp1 = 0
        ElseIf DL(i, 1) <> "" Then
            CongViec = i
            KQ(CongViec, 1) = Tmp2
            Tmp2 = 0
        ElseIf DL(i, 3) <> "" Then
            DL(i, 9) = DL(i, 7) * DL(i, 8)
        End If
    Next
    [I4].Resize(UBound(DL, 1)).Value = KQ
End Sub

Nhìn các anh nmhung49, trungvdb, bạn hoamattroicoi làm veo veo mà thấy thẹn quá
Thấy kg nhờ mình nhưng nói thật là bạn nên đi từ từ, những bài for ngược này và tư duy hơi cao thì khoan đã.
PHP:
Sub Ttoan01()
    Dim KQ, DL(), i As Long, Tmp1 As Double, Tmp2 As Double
    dongcuoi = [G65000].End(xlUp).Row
    DL = Range("A4:H" & dongcuoi).Value
    Range("I4:I1000").ClearContents
    ReDim KQ(1 To UBound(DL, 1), 1 To 1)
    For i = UBound(DL, 1) To 1 Step -1
      If DL(i, 1) = "" And DL(i, 2) = "" Then
        If DL(i, 3) <> "" Then
          KQ(i, 1) = DL(i, 7) * DL(i, 8)
          Tmp1 = Tmp1 + KQ(i, 1)
        Else
          If DL(i, 4) <> "" Then
            KQ(i, 1) = Tmp1
            Tmp2 = Tmp2 + Tmp1
            Tmp1 = 0
          End If
        End If
      Else
        KQ(i, 1) = Tmp2
        Tmp2 = 0
      End If
    Next
    [K4].Resize(UBound(DL, 1)).Value = KQ
End Sub
 
Upvote 0
Chán quá, không hiểu sao mảng khó thế nhìn các bác trên diễn đàn làm ngon thế mà khi lao vào làm mới thấy khó thật, hôm nay sưu tầm các bài trên diễn đàn về làm nhưng sai nhiều quá.

Tôi lấy thử bài toán nhỏ:
- Cột I = Cột H x Cột G (Thành tiền = đơn giá x khối lượng định mức)
- Thành tiền mỗi công việc = VL+NC+MTC

Tôi viết Code như sau, trình độ còi quá không biết sai kiến thức cơ bản ở chỗ nào mà không biết
PHP:
Sub TT()
Dim VungDL, Mahieu As Long, DVi As Long, iRow As Long
With Sheet1.Range("A4:I21")
    VungDL = .Value
For iRow = 1 To UBound(VungDL, 1)
    If VungDL(iRow, 2) <> "" Then
        Mahieu = iRow
    End If
    If VungDL(iRow, 4) <> "" And VungDL(iRow, 5) = "" Then
        DVi = iRow
    End If
    If VungDL(iRow, 3) <> "" Then
        VungDL(iRow, 9) = VungDL(iRow, 7) * VungDL(iRow, 8)
        VungDL(DVi, 9) = VungDL(iRow, 9) + VungDL(DVi, 9)
        VungDL(Mahieu, 9) = VungDL(iRow, 9) + VungDL(Mahieu, 9)
    End If
Next iRow
.Value = VungDL
End With
End Sub

Bạn có thể tham khảo cách này cũng được
To Lindan hồi xưa mình cũng nhưng bạn thôi từ từ nhen bạn
 

File đính kèm

Upvote 0
Tôi thử làm đi từ trên xuống dưới, kết quả ra gần như chuẩn nhưng không hiểu tại sao kết quả I4 lại sai, nhờ các bạn chỉ hộ tôi nguyên nhân

PHP:
Sub Ttoan()
    Dim Vung, DL(), i As Long, Nhom As Long, CongViec As Long, Tmp1, Tmp2, heso
    dongcuoi = [G65000].End(xlUp).Row
    Set Vung = Range("A4:I" & dongcuoi)
    DL = Vung.Value
    Range("I4:I" & dongcuoi).ClearContents
    ReDim KQ(1 To UBound(DL, 1), 1 To 1)
    For i = 1 To UBound(DL, 1)
        If DL(i, 1) <> "" Then
            CongViec = i
            Tmp2 = 0
        ElseIf DL(i, 1) = "" And DL(i, 3) = "" Then
            Nhom = i
            heso = DL(i, 7)
            Tmp2 = Tmp2 + Tmp1
            KQ(CongViec, 1) = Tmp2
            Tmp1 = 0
        ElseIf DL(i, 4) = "V" & ChrW(7853) & "t li" & ChrW(7879) & "u khác" Then
            DL(i, 9) = 15 / 100 * Tmp1
        ElseIf DL(i, 3) <> "" Then
            KQ(i, 1) = heso * DL(i, 7) * DL(i, 8)
            Tmp1 = KQ(i, 1) + Tmp1
            KQ(Nhom, 1) = Tmp1
        End If
    Next
    [I4].Resize(UBound(DL, 1)).Value = KQ
End Sub
 

File đính kèm

Upvote 0
Bài toán gốc của bài này không phải đơn giản

Theo tôi biết, tác giả đưa đầu bài không rõ ràng, dẫn đến lời giải chưa tính đến các ô màu đỏ trong đầu đề bài toán:

- Đối với vật liệu, nhân công, máy đều có hệ số (1; 3,36; 1,4) nên sau khi tổng cộng phải nhân với hệ số
- Đối với vật liệu khác: được tính bằng 1,5% các vật liệu chính;
- Bài toán gốc trên diễn đàn thì mỗi công việc đều có Chi phí trực tiếp khác xác định bằng 1,5%(VL+NC+MTC)

Kết quả đúng bài toán sẽ hình sau
Baitoangoc.jpg




Tôi làm thử nhưng viết Code để tính thành phần chí phí trực tiếp khác nhưng làm mãi không được, kính nhờ các bác giúp cho một tay.
 

File đính kèm

Upvote 0
Theo tôi biết, tác giả đưa đầu bài không rõ ràng, dẫn đến lời giải chưa tính đến các ô màu đỏ trong đầu đề bài toán:
.

Cho mình hỏi không phải một chút bài này bắt đầu từ đâu nhỉ. mong mọi người chỉ giúp
Xin lỗi mọi người chắc mình quá vô duyên!:=\+
 
Lần chỉnh sửa cuối:
Upvote 0
Tức bài này điền dữ liệu vào cột I đối với từng công việc chị ah (hình trên là kết quả minh hoạ), số dòng cần điền rất nhiều, mong chị giúp cho.
 
Upvote 0
Mình cũng chưa hiểu rõ ý bạn lắm nhưng mình cũng làm tạm một file Excel theo công việc mà bạn nêu ra, bạn có thể thay đổi dữ liệu cho phù hợp với công việc của mình. Mình cũng chuyển tổng hợp sang Sheet "Du thau" các công việc. Bạn có thể kiểm tra thử
P\S: nhấn Ctrl + Q để chạy nhé chúc bạn thành công! --=0
 

File đính kèm

Upvote 0
Tôi chưa hiểu về Sfomula = "=" & Right(str, Len(str) - 1), tại sao lại trừ 1? Mong chị Ngọc Lan và mọi người giải thích dùm
PHP:
Public Function Sfomula(ByVal MySheet As Worksheet, slower As Long, sUpper As Long) As String

    Dim i As Long, str As String

    str = ""

    For i = slower To sUpper

        Select Case MySheet.Cells(i, 4)
            Case UNC("VËt liÖu"), UNC("Nh©n c«ng"), UNC("M¸y thi c«ng"), UNC("Trùc tiÕp phÝ kh¸c")
                str = str + "+" + MySheet.Cells(i, 9).Address(0, 0)
        End Select

        If MySheet.Cells(i, 1) <> vbNullString Then Exit For

    Next

    Sfomula = "=" & Right(str, Len(str) - 1)

End Function
 
Upvote 0
Tôi chưa hiểu về Sfomula = "=" & Right(str, Len(str) - 1), tại sao lại trừ 1? Mong chị Ngọc Lan và mọi người giải thích dùm

Vì khi thực hiện lệnh trong vòng lặp str = str + "+" + MySheet.Cells(i, 9).Address(0, 0) biến str đã dư ra một dấu "+" đằng trước thôi mà
 
Upvote 0
Xin nhờ mọi người giải thích dùm đoạn Code:

PHP:
Function Dconcatenate(ParamArray cel() As Variant) As String
    For N = LBound(cel) To UBound(cel)
        For i = 1 To cel(N).Rows.Count
            For j = 1 To cel(N).Columns.Count
                Ketqua = Ketqua & "," & cel(N)(i, j)
            Next
        Next
        Ketquachung = Ketquachung & "," & Ketqua
    Next
    Ketquachung = Right(Ketquachung, Len(Ketquachung) - 2)
    Dconcatenate = Ketquachung
End Function

Tại sao dòng Right(Ketquachung, Len(Ketquachung) - 2) lại trừ đi 2 nhỉ?
 
Upvote 0
Xin nhờ mọi người giải thích dùm đoạn Code:

PHP:
Function Dconcatenate(ParamArray cel() As Variant) As String
    For N = LBound(cel) To UBound(cel)
        For i = 1 To cel(N).Rows.Count
            For j = 1 To cel(N).Columns.Count
                Ketqua = Ketqua & "," & cel(N)(i, j)
            Next
        Next
        Ketquachung = Ketquachung & "," & Ketqua
    Next
    Ketquachung = Right(Ketquachung, Len(Ketquachung) - 2)
    Dconcatenate = Ketquachung
End Function

Tại sao dòng Right(Ketquachung, Len(Ketquachung) - 2) lại trừ đi 2 nhỉ?

Bạn để ý 2 dòng này

PHP:
...
Ketqua = Ketqua & "," & cel(N)(i, j)
...
Ketquachung = Ketquachung & "," & Ketqua
Bạn sẽ thấy ban đầu, biến Ketqua không có gì hết nên nó sẽ có dạng là ",abcxyz"
Sau đó nạp vào biến Ketquachung mà Ketquachung ban đầu không có gì, thành ra nó sẽ là ",,abcxyz"
Do đó để kết quả đúng thì phải lấy từ bên phải qua mà Len(ketquachung)-2 đi tức là chỉ còn "abcxyz".
 
Upvote 0
Dictionary của em sai ở đâu mà không được nhỉ

Tập làm Dictionary, em làm thử lại ví dụ của thày Ndu nhưng không hiểu sao chạy không nổi vậy, xin được góp ý thêm để hoàn thiện Code (khi chạy nó báo #NAME?):

PHP:
Function UniqueList(SrcArray)
    Dim Item
    Set Dic = CreateObject("Scripting.Dictionary")
    Tmp = SrcArray.Value      'co tac dung chuyen Range thanh Variant
    For Each Item In Tmp
        If Not Dic.Exists(Item) And Item <> "" Then
            Dic.Add Item, ""
        End If
    Next
    UniqueList = .Keys
End Function
 
Lần chỉnh sửa cuối:
Upvote 0
Tập làm Dictionary, em làm thử lại ví dụ của thày Ndu nhưng không hiểu sao chạy không nổi vậy, xin được góp ý thêm để hoàn thiện Code (khi chạy nó báo #NAME?):
1. Function phải để trong module mới xài trên sheet được

2. Câu lệnh
UniqueList = .Keys
chắc chắn sẽ báo lỗi vì không có With - End With

3. Biến Tmp và biến Dic chưa khai báo

4. Do function sử dụng trên sheet (lấy value từ ScrArray), nên tốt hơn là nên khai báo
Function UniqueList(SrcArray As Range)

5. Nếu lấy Dic.Keys để gán xuống sheet, sẽ được kết quả nằm ngang. Tô dọc rồi gõ hàm sẽ chỉ ra kết quả đầu tiên.
 
Lần chỉnh sửa cuối:
Upvote 0
Tập làm Dictionary, em làm thử lại ví dụ của thày Ndu nhưng không hiểu sao chạy không nổi vậy, xin được góp ý thêm để hoàn thiện Code (khi chạy nó báo #NAME?):

PHP:
Function UniqueList(SrcArray)
    Dim Item
    Set Dic = CreateObject("Scripting.Dictionary")
    Tmp = SrcArray.Value      'co tac dung chuyen Range thanh Variant
    For Each Item In Tmp
        If Not Dic.Exists(Item) And Item <> "" Then
            Dic.Add Item, ""
        End If
    Next
    UniqueList = .Keys
End Function
UniqueList = .Keys là cái gì? Phải là UniqueList = Dic.Keys chứ
Ngoài ra nên sửa Tmp = SrcArray.Value thành Tmp = SrcArray (lỡ SrcArray không phải là Range thì câu lệnh ấy sẽ báo lỗi)
 
Upvote 0
PHP:
Function UniqueList(SrcArray)
    Dim Item
    Set Dic = CreateObject("Scripting.Dictionary")
    Tmp = SrcArray
    For Each Item In Tmp
        If Not Dic.Exists(Item) And Item <> "" Then
            Dic.Add Item, ""
        End If
    Next
    UniqueList = Dic.Keys
End Function

Lỗi Code thì thày Ndu đã nói ở trên rồi, nhưng bạn nhớ UniqueList = Dic.Keys nó là 1 mảng chứ không phải là 1 giá trị đơn đâu nhé.

Ví dụ: không dùng được UniqueList(A1:A3) trực tiếp đâu, mà cách dùng phải cho nó đi kèm với hàm nào đó ví dụ Counta(UniqueList(A1:A3)) hoặc là phải gán chuyển thành Range (thông qua thủ tục Sub).

Chú ý: Keys khác với key
 
Lần chỉnh sửa cuối:
Upvote 0
Lỗi Code thì thày Ndu đã nói ở trên rồi, nhưng bạn nhớ UniqueList = Dic.Keys nó là 1 mảng chứ không phải là 1 giá trị đơn đâu nhé.

Ví dụ: không dùng được UniqueList(A1:A3) trực tiếp đâu, mà cách dùng phải cho nó đi kèm với hàm nào đó ví dụ Counta(UniqueList(A1:A3)) hoặc là phải gán chuyển thành Range (thông qua thủ tục Sub).

Hàm mảng thì xài kiểu mảng chứ ai nói không được:

Có thể tô 10 ô hàng ngang và gõ = UniqueList(A1:A10), nhấn Ctrl Shift Enter
 
Upvote 0
Em thử làm truyền tham số bằng Sub, Code này của em chạy không hiểu sao ô cuối bằng #N/A
PHP:
Function UniqueList(SrcArray)
    Dim Item
    Set Dic = CreateObject("Scripting.Dictionary")
    tmp = SrcArray
    For Each Item In tmp
        If Not Dic.Exists(Item) And Item <> "" Then
            Dic.Add Item, ""
        End If
    Next
    UniqueList = Dic.Keys
End Function

PHP:
Sub Loc()
  Dim Arr, tmp, i As Long
  tmp = UniqueList(Sheet1.Range("A2:B50"))
  If IsArray(tmp) Then
    ReDim Arr(1 To UBound(tmp), 1 To 1)
    For i = 1 To UBound(tmp)
          Arr(i, 1) = tmp(i)
    Next
    Sheet2.Range("A1").Resize(i).Value = Arr
  End If
End Sub

-----------------
Em cứ có cảm giác có gì đó không ổn lắm, việc lặp lại 2 dòng này có vẻ như mâu thuẫn nhau thì phải
PHP:
tmp = SrcArray
xuống dưới lại có

PHP:
tmp = UniqueList(Sheet1.Range("A2:B50"))
 
Lần chỉnh sửa cuối:
Upvote 0
Em thử làm truyền tham số bằng Sub, Code này của em chạy không hiểu sao ô cuối bằng #N/A
PHP:
Function UniqueList(SrcArray)
    Dim Item
    Set Dic = CreateObject("Scripting.Dictionary")
    tmp = SrcArray
    For Each Item In tmp
        If Not Dic.Exists(Item) And Item <> "" Then
            Dic.Add Item, ""
        End If
    Next
    UniqueList = Dic.Keys
End Function

PHP:
Sub Loc()
  Dim Arr, tmp, i As Long
  tmp = UniqueList(Sheet1.Range("A2:B50"))
  If IsArray(tmp) Then
    ReDim Arr(1 To UBound(tmp), 1 To 1)
    For i = 1 To UBound(tmp)
          Arr(i, 1) = tmp(i)
    Next
    Sheet2.Range("A1").Resize(i).Value = Arr
  End If
End Sub

-----------------
Em cứ có cảm giác có gì đó không ổn lắm, việc lặp lại 2 dòng này có vẻ như mâu thuẫn nhau thì phải
PHP:
tmp = SrcArray
xuống dưới lại có

PHP:
tmp = UniqueList(Sheet1.Range("A2:B50"))
1. Bạn đưa file của bạn để mọi người test cho tiện. Khi code thực hiện
Sheet2.Range("A1").Resize(i).Value = Arr
thì i=Ubound(Tmp)+1 (mặt dù Fori=1 To UBound(tmp))
2. bạn sửa
Arr(i, 1) = tmp(i-1) vì Tmp() luôn bắt đầu bằng 0 chứ không phải là 1
 
Lần chỉnh sửa cuối:
Upvote 0
Theo tôi, bạn sửa thử thành thế này

PHP:
Function UniqueList(SrcArray)
    Dim Item
    Set Dic = CreateObject("Scripting.Dictionary")
    SubArr = SrcArray
    For Each Item In SubArr
        If Not Dic.Exists(Item) And Item <> "" Then
            Dic.Add Item, ""
        End If
    Next
    UniqueList = Dic.Keys
End Function

PHP:
Sub Loc()

    Dim Arr, tmp, i As Long
    tmp = UniqueList(Sheet1.Range("A2:B50"))
    ReDim Arr(1 To UBound(tmp) + 1, 1 To 1)
    For i = 0 To UBound(tmp)
        Arr(i + 1, 1) = tmp(i)
    Next
    Sheet2.Range("A1").Resize(i).Value = Arr
End Sub
 

File đính kèm

Upvote 0
Em chưa hiểu đoạn này, xin bác nói rõ giúp em hiểu với ah, đặc biệt là chỗ bôi đậm

1. Bạn đưa file của bạn để mọi người test cho tiện. Khi code thực hiện
Sheet2.Range("A1").Resize(i).Value = Arr
thì i=Ubound(Tmp)+1 (mặt dù Fori=1 To UBound(tmp))
 
Upvote 0
Em chưa hiểu đoạn này, xin bác nói rõ giúp em hiểu với ah, đặc biệt là chỗ bôi đậm
i sẽ tăng lên 1, sau đó mới kiểm tra nó thỏa mãn cận cuối không, nếu chưa đạt thì code chạy tiếp, ngược lại nó sẽ thoát vòng lập. Nghĩa là khi i=Ubound(Tmp) thì vẫn thỏa mãn nên code vẫn chạy, sau đó i tăng lên 1 là Ubound(Tmp)+1 vượt cận cuối nên thoát vòng For. lệnh cuối cùng liên quan đến i sẽ là Ubound(Tmp)+1 (ví dụ: For i=1 to 5, sau khi kết thúc vòng lập thì i=6 )
Tóm lại i tăng trước và kiểm tra điều kiện sau
 
Lần chỉnh sửa cuối:
Upvote 0
Phần mảng em vẫn còn lơ mơ, em Test thử thế này
PHP:
Sub thunghiem()
Set Vung = Range("A1:A100")
DL = Vung.Value
MsgBox UBound(DL, 1)
End Sub

Sao kết quả ra 100 nhỉ?

em cứ tưởng ra 99 vì phần tử đầu tiên nó là phần tử 0 chứ (vì mảng phần tử bắt đầu bao giờ cũng là 0 mà)?
 
Upvote 0
Phần mảng em vẫn còn lơ mơ, em Test thử thế này
PHP:
Sub thunghiem()
Set Vung = Range("A1:A100")
DL = Vung.Value
MsgBox UBound(DL, 1)
End Sub

Sao kết quả ra 100 nhỉ?

em cứ tưởng ra 99 vì phần tử đầu tiên nó là phần tử 0 chứ (vì mảng phần tử bắt đầu bao giờ cũng là 0 mà)?
Bạn chú ý Ubound() là phần tử cuối cùng chứ không phải là số phần tử, số phần tử = Ubound()-Lbound()+1, trường hợp trên 100 là đúng rồi, phần tử đầu tiên là 1, phần tử cuối là 100
 
Upvote 0
Em vẫn còn chưa rõ một số khái niệm về mảng 1 chiều và 2 chiều

Code này em chạy không có vấn đề gì

PHP:
Function UniqueList(sArray)
    Dim SubArr, Item
    SubArr = sArray
    Set Dic = CreateObject("Scripting.Dictionary")
    For Each Item In SubArr
        If Item <> "" And Not Dic.Exists(Item) Then
            Dic.Add Item, ""
        End If
    Next
    UniqueList = Dic.Keys
End Function

PHP:
Sub Loc()
    Dim Tmp()
    Tmp = UniqueList(Sheet1.Range("A1:B50000"))
    ReDim Arr(1 To UBound(Tmp, 1) + 1, 1 To 1)
    For i = 0 To UBound(Tmp, 1)
        Arr(i + 1, 1) = Tmp(i)
    Next
    Sheets("Sheet2").[A1].Resize(i) = Arr
End Sub

Nhưng em thử thay 2 dòng

PHP:
Dim SubArr
Arr(i + 1, 1) = Tmp(i)

bằng
PHP:
Dim SubArr()
Arr(i + 1, 1) = Tmp(i,1)
thì bị lỗi ngay

--------------
Vì em vẫn nghĩ: Tmp(i)=Tmp(i,1)
SubArr là mảng thì khi khai báo Dim SubArr() và Dim SubArr có gì khác nhau ah?
 
Upvote 0
Em vẫn còn chưa rõ một số khái niệm về mảng 1 chiều và 2 chiều

Code này em chạy không có vấn đề gì

PHP:
Function UniqueList(sArray)
    Dim SubArr, Item
    SubArr = sArray
    Set Dic = CreateObject("Scripting.Dictionary")
    For Each Item In SubArr
        If Item <> "" And Not Dic.Exists(Item) Then
            Dic.Add Item, ""
        End If
    Next
    UniqueList = Dic.Keys
End Function

PHP:
Sub Loc()
    Dim Tmp()
    Tmp = UniqueList(Sheet1.Range("A1:B50000"))
    ReDim Arr(1 To UBound(Tmp, 1) + 1, 1 To 1)
    For i = 0 To UBound(Tmp, 1)
        Arr(i + 1, 1) = Tmp(i)
    Next
    Sheets("Sheet2").[A1].Resize(i) = Arr
End Sub

Nhưng em thử thay 2 dòng

PHP:
Dim SubArr
Arr(i + 1, 1) = Tmp(i)

bằng
PHP:
Dim SubArr()
Arr(i + 1, 1) = Tmp(i,1)
thì bị lỗi ngay

--------------
Vì em vẫn nghĩ: Tmp(i)=Tmp(i,1)
SubArr là mảng thì khi khai báo Dim SubArr() và Dim SubArr có gì khác nhau ah?
Tmp() lấy từ UniqueList() và UniqueList() lấy từ Dic.Keys, mà Dic.Keys là mãng 1 chiều nên mãng Tmp() là mãng 1 chiều vì vậy không thể dùng Tmp(i,1)
 
Upvote 0
Nhưng em thử thay 2 dòng
PHP:
Dim SubArr
Arr(i + 1, 1) = Tmp(i)
bằng
PHP:
Dim SubArr()
Arr(i + 1, 1) = Tmp(i,1)
thì bị lỗi ngay

--------------
Vì em vẫn nghĩ: Tmp(i)=Tmp(i,1)
SubArr là mảng thì khi khai báo Dim SubArr() và Dim SubArr có gì khác nhau ah?
Biến Tmp nếu ghi thành Tmp(i, 1) thì bạn đã ngầm xem nó là mảng 2 chiều rồi ---> Sai (như vietohoai đã phân tích)
Còn về biến SubArr, là do bạn làm mọi thứ quá vắn tắt... Nếu đi từng bước thế này thì sẽ không có chuyện gì xảy ra:
Mã:
Sub Loc()
  Dim tmp(), i As Long, sArray
  [COLOR=#ff0000]sArray = Sheet1.Range("A1:B50000")[/COLOR]
  [COLOR=#ff0000]tmp = UniqueList(sArray)[/COLOR]
  ReDim Arr(1 To UBound(tmp, 1) + 1, 1 To 1)
  For i = 0 To UBound(tmp, 1)
    Arr(i + 1, 1) = tmp(i)
  Next
  Sheet1.[F1].Resize(i) = Arr
End Sub
-------------
Nói thêm: Bạn luôn sơ suất trong phần khai báo biến (không khai báo đầy đủ) ---> Sau này chú ý thêm vấn đề này... vì không phải cứ thấy code chạy được là xem như ta đã thành công đâu
 
Upvote 0
Thưa thày em tưởng sArray nó là tham số của hàm UniqueList thì không nên khai báo cụ thể:

PHP:
sArray = Sheet1.Range("A1:B50000")

Mà nó sẽ được ngầm hiểu thông qua Tmp ở câu:
PHP:
Tmp = UniqueList(Sheet1.Range("A1:B50000"))

-----------
Xin thày giảng giải cho tại sao khi khai báo như của thày ở trên thì không bị lỗi khi thay Dim SubArr bằng Dim SubArr() .
 
Lần chỉnh sửa cuối:
Upvote 0
Thưa thày em tưởng sArray nó là tham số của hàm UniqueList thì không nên khai báo cụ thể:

PHP:
sArray = Sheet1.Range("A1:B50000")

Mà nó sẽ được ngầm hiểu thông qua Tmp ở câu:
PHP:
Tmp = UniqueList(Sheet1.Range("A1:B50000"))

-----------
Xin thày giảng giải cho tại sao khi khai báo như của thày ở trên thì không bị lỗi khi thay Dim SubArr bằng Dim SubArr() .
Range và Array tuy có thể chuyển đổi qua lại nhưng trong 1 vài trường hợp cụ thế nó có phân biệt... Vậy ta nên tự mình chuyển đổi, đừng bắt code phải "ngầm hiểu" như bạn nói
Giống như bài toán đố vui tại đây:
http://www.giaiphapexcel.com/forum/showthread.php?7146-Đố-vui-về-VBA!&p=232941#post232941
Nếu ta không chuyển trước (bằng phép biến đổi Temp = SrcArray) thì code sẽ chạy sai
-------------
Nói tóm lại: Nếu "cải tiến" không như ý thì hãy trở về với các bước cơ bản
Sau này trong các bài toán lớn, bạn sẽ còn gặp những vụ tương tự rất thường xuyên mà nếu không làm đúng thứ tự sẽ lỗi tùm lum các nơi đến mức không còn biết đường nào mà lần...
 
Upvote 0
Mình xin nói thêm chổ này
Dim SubArr()

Tmp = UniqueList(Sheet1.Range("A1:B50000"))
Nếu bạn vẫn muốn giữ nguyên chúng, không muốn thêm biến sArray thì hãy sửa đoán gán biến Tmp thành:
Tmp = UniqueList(Sheet1.Range("A1:B50000").Value)
(tức là đằng nào cũng phải chuyển Range thành Array)
 
Upvote 0
Giúp em bài toán về lọc duy nhất, sau đó nối các phần tử duy nhất đó

Em xin gửi file đính kèm 9 (đầu vào của em cột A, kết quả minh họa tại ô D1)

Em làm như sau không được

PHP:
Function Connection(FindRng As Range)
    Dim i As Long, j As Long, Arr(), Tmp, Dic
    Set Dic = CreateObject("Scripting.Dictionary")
    For i = 1 To FindRng.Rows.Count
        If FindRng.Value <> "" Then
            Tmp = FindRng
            If Not Dic.Exists(Tmp) Then
                j = j + 1
                Dic.Add Tmp, j
            End If
        End If
        ReDim Preserve Arr(1 To j)
        Arr(Dic.Item(Tmp)) = Tmp
    Next
    Connection = Join(Arr, ",")
End Function

Rất mong mọi ngưởi chỉ cho em chỗ sai để em khắc phục
----------
em chưa rõ lắm về cách dùng của Preserve, xin được chỉ bảo.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Em xin gửi file đính kèm 9 (đầu vào của em cột A, kết quả minh họa tại ô D1)

Em làm như sau không được

PHP:
Function Connection(FindRng As Range)
    Dim i As Long, j As Long, Arr(), Tmp, Dic
    Set Dic = CreateObject("Scripting.Dictionary")
    For i = 1 To FindRng.Rows.Count
        If FindRng.Value <> "" Then
            Tmp = FindRng
            If Not Dic.Exists(Tmp) Then
                j = j + 1
                Dic.Add Tmp, j
            End If
        End If
        ReDim Preserve Arr(1 To j)
        Arr(Dic.Item(Tmp)) = Tmp
    Next
    Connection = Join(Arr, ",")
End Function

Rất mong mọi ngưởi chỉ cho em chỗ sai để em khắc phục
----------
em chưa rõ lắm về cách dùng của Preserve, xin được chỉ bảo.
Sai cả rổ luôn!
Vầy mới đúng nè:
PHP:
Function Connection(byVal FindRng As Range) As String
  Dim tmp As String, Dic, sArray, Item
  sArray = FindRng.Value
  Set Dic = CreateObject("Scripting.Dictionary")
  For Each Item In sArray
    If Trim(CStr(Item)) <> "" Then
      tmp = Trim(CStr(Item))
      If Not Dic.Exists(tmp) Then Dic.Add tmp, ""
    End If
  Next
  If Dic.Count Then Connection = Join(Dic.Keys, ",")
End Function
 
Upvote 0
Em biết chỗ nhầm FindRng nó là một mảng chứ không phải 1 ô nên nếu dùng

PHP:
If FindRng.Value <> "" Then
là sai
Code của thày quá chuẩn rồi, ở đây em thử làm theo hướng khác xem bởi em đang tìm hiểu về Preserve, em sửa thành thế này cũng được thày ah

PHP:
Function Connection(FindRng As Range)
    Dim i As Long, j As Long, Arr(), Tmp, Dic
    Set Dic = CreateObject("Scripting.Dictionary")
    For i = 1 To FindRng.Rows.Count
        If FindRng(i, 1) <> "" Then
            Tmp = FindRng(i, 1)
            If Not Dic.Exists(Tmp) Then
                j = j + 1
                Dic.Add Tmp, j
            End If
        End If
        ReDim Preserve Arr(1 To j)
        Arr(Dic.Item(Tmp)) = Tmp
    Next
    Connection = Join(Arr, ",")
End Function

-----------
Em đọc các tài liệu mà chưa tìm được khi nào người ta dùng Preserve, ở trên em bắt chước máy móc nhưng không hiểu lắm, xin thày chỉ cho
 
Lần chỉnh sửa cuối:
Upvote 0
Giả sử em nối tất cả các ô bằng dấu phảy (,), những ô trùng lặp đều được cả tức không tính yếu tố duy nhất.

Em viết thế này chắc chắn là sai, nhưng em chưa hiểu lắm tại sao nó sai, xin thày và mọi người chỉ dạy

PHP:
Function Connection(ByVal FindRng As Range) As String
  Dim sArray
  sArray = FindRng.Value
  Connection = Join(sArray, ",")
End Function
 
Upvote 0
Em đọc các tài liệu mà chưa tìm được khi nào người ta dùng Preserve, ở trên em bắt chước máy móc nhưng không hiểu lắm, xin thày chỉ cho
Nếu dùng mảng thì buộc khải khai báo số chiều + số phần tử trong mảng trước
- Trường hợp bạn biết trước số phần tử trong mảng thì chỉ cần ReDim Arr(số phần tử) là đủ
- Trường hợp bạn không biết trước số phần tử thì dùng ReDim Preserve... nghĩa là làm đến đâu, mở rổng mảng đến nấy
(đương nhiên đang nói trên cơ sở mảng 1 chiều, với mảng 2 chiều hoặc nhiều chiều thì có khác hơn 1 chút ---> Chỉ mở rộng được chiều cuối cùng khi dùng ReDim Preserve)
------------------
Giả sử em nối tất cả các ô bằng dấu phảy (,), những ô trùng lặp đều được cả tức không tính yếu tố duy nhất.

Em viết thế này chắc chắn là sai, nhưng em chưa hiểu lắm tại sao nó sai, xin thày và mọi người chỉ dạy

PHP:
Function Connection(ByVal FindRng As Range) As String
  Dim sArray
  sArray = FindRng.Value
  Connection = Join(sArray, ",")
End Function
Đương nhiên không được rồi (thí nghiệm sẽ biết liền) vì hàm Join chỉ làm việc với mảng 1 chiều mà thôi... Với Range, cho dù đã chuyển thành mảng rồi thì nó vẫn không phải mảng 1 chiều (nó luôn là mảng 2 chiều) nên dùng Join sẽ báo lỗi
Vậy, trước khi dùng Join, hãy For... Next để chuyển các phần tử trong Range vào mảng 1 chiều cái đã
 
Lần chỉnh sửa cuối:
Upvote 0
Tức là Preserve thì ban đầu khai thiếu số phần tử cũng không sao, sau khi tính toán nó tự động thêm phần tử cho mình hả thày.

---

Nếu vậy bài nào mình cũng cho tên này vào (ReDim Preserve) cho chắc ăn thì có vấn đề gì không ah?
 
Upvote 0
Tức là Preserve thì ban đầu khai thiếu số phần tử cũng không sao, sau khi tính toán nó tự động thêm phần tử cho mình hả thày.
Đúng vậy!
Nếu vậy bài nào mình cũng cho tên này vào (ReDim Preserve) cho chắc ăn thì có vấn đề gì không ah?
Tùy theo trường hợp bạn ơi... Nó còn liên quan đến tốc độ nữa đấy
Nói chung: Dùng cái gì cũng được, quan trọng là thích hợp, đúng lúc, đúng chổ ---> Đó mới là GIẢI QUYẾT HIỆU QUẢ
 
Upvote 0
Thầy Ndu ơi, Thầy coi làm giúp em bài này nhe Thầy!
 

File đính kèm

Upvote 0
Thầy Ndu ơi, Thầy coi làm giúp em bài này nhe Thầy!
Bài của bạn thuộc dạng trích lọc, hơn nữa nó lại có liên quan đến kế toán
Vậy bạn phải cho vào box liên quan đến trích lọc hoặc kế toán chứ, sao lại cho vào topic này?
Quăng bài tùm lum sẽ bị xóa đấy nhé!
 
Upvote 0
Xin lỗi Thầy vì em nôn quá nên đưa bài ra 2 topic, mong Thầy và DĐ tha lỗi, em sẽ đưa qua box trích lọc.
 
Upvote 0
Em có dữ liệu từ A1:A10 sheet 1 là dạng text (kiểu số) ví dụ
201202
201203
..........

Em đang thử dùng mảng để tìm ra ô là nào là số nhưng chưa được
Anh chị sửa code giúp em với

PHP:
Sub test()
Dim sArr()
    sArr = Sheet1.Range("A1:A10").Value
    For i = 1 To UBound(sArr, 1)
        If sArr(i, 1) <> "" Then
           If IsNumeric(sArr(i, 1)) Then
              MsgBox "Sheet1 dong thu" & i & " format la so "
              Exit Sub
           End If
        End If
    Next i
  
End Sub
 

File đính kèm

Upvote 0
Em có dữ liệu từ A1:A10 sheet 1 là dạng text (kiểu số) ví dụ
201202
201203
..........

Em đang thử dùng mảng để tìm ra ô là nào là số nhưng chưa được
Anh chị sửa code giúp em với

PHP:
Sub test()
Dim sArr()
    sArr = Sheet1.Range("A1:A10").Value
    For i = 1 To UBound(sArr, 1)
        If sArr(i, 1) <> "" Then
           If IsNumeric(sArr(i, 1)) Then
              MsgBox "Sheet1 dong thu" & i & " format la so "
              Exit Sub
           End If
        End If
    Next i
  
End Sub
Thay IsNumeric bằng WorksheetFunction.IsNumber thử xem
 
Upvote 0
Thay IsNumeric bằng WorksheetFunction.IsNumber thử xem

Ẹc, được Anh NDU ạh.
EM nhớ có lần anh dặn, không nên dùng công thức excel trong VBA. Việc này sẽ làm chậm file

Em đã test thử với hơn 10.000 dòng. thấy ok anh ạh

Cám ơn Anh nhé
Qua ví dụ này chứng tở isnumeric không chơi với mảng
 
Upvote 0

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

Back
Top Bottom