Dạng bài này có trên GPE lâu rồiBài này thường ngày tôi làm bằng Pivot table, nay tôi muốn học thêm VBA nhờ các bác làm giúp.
Xin cảm ơn rất nhiều
Xem file này, tôi vận dụng code của NDU.Chà chà file này nặng quá, máy của tôi sau khi mở chọn hàm max để tính, không hiểu sao 3 phút rồi mà chưa xong.
Bạn thử file mới này xem thế nào nhéChà chà file này nặng quá, máy của tôi sau khi mở chọn hàm max để tính, không hiểu sao 3 phút rồi mà chưa xong.
Qua bài transferData_5 của NDU mới thấy lợi hại của việc khai báo số dòng và cột của mảng. Khai dư quá thì chậm hơn khai vừa đủ và nếu cần thì dùng redim.Bạn thử file mới này xem thế nào nhé
Code đã được cải tiến thêm rất nhiều. Máy tôi cho ra kết quả trong vòng 0.7 giây với dữ liệu 65000 dòng
Tôi thấy trên diễn đàn, có bài toán bao gồm 2 Sub trở lên, thường có 2 phương án:
- Từng Sub trên một Module (Module1, Module 2...)
- Gộp chung các Sub vào trong 1 Module
Xin hỏi trong 2 cách trên thì cách nào thuận tiện hơn.
Sub TaoBC()
Dim endR&, i&, iR&, iC&, nR&, nC&
Dim Arr, ArrKQ
Dim Tmp01$, Tmp02$
Dim Dic01 As Object, Dic02 As Object
Set Dic01 = CreateObject("Scripting.Dictionary")
Set Dic02 = CreateObject("Scripting.Dictionary")
With Sheets("Data")
.AutoFilterMode = False
endR = .Cells(65000, 1).End(3).Row
Arr = .Range(.Cells(2, 1), .Cells(endR, 3)).Value
End With
ReDim ArrKQ(1 To UBound(Arr), 1 To 200)
iR = 1: iC = 1
For i = 1 To UBound(Arr)
If Len(CStr(Arr(i, 1))) > 0 Then
If Len(CStr(Arr(i, 2))) > 0 Then
Tmp01 = CStr(Arr(i, 1))
If Not Dic01.Exists(Tmp01) Then
iR = iR + 1
Dic01.Add Tmp01, iR
ArrKQ(iR, 1) = Tmp01
End If
Tmp02 = Arr(i, 2)
If Not Dic02.Exists(Tmp02) Then
iC = iC + 1
Dic02.Add Tmp02, iC
ArrKQ(1, iC) = Tmp02
End If
nR = Dic01.Item(Tmp01)
nC = Dic02.Item(Tmp02)
ArrKQ(nR, nC) = ArrKQ(nR, nC) + Arr(i, 3)
End If
End If
Next i
If iR And iC Then
With Sheets("sheet2")
.Cells.ClearContents
.[A1].Resize(iR, iC) = ArrKQ
End With
End If
Erase Arr, ArrKQ
Set Dic01 = Nothing: Set Dic02 = Nothing
End Sub
Bạn muốn đặt sao tùy thích. Riêng tôi, nếu chỉ có 2 Sub thì chẳng việc gì chia ra 2 moduleTôi thấy trên diễn đàn, có bài toán bao gồm 2 Sub trở lên, thường có 2 phương án:
- Từng Sub trên một Module (Module1, Module 2...)
- Gộp chung các Sub vào trong 1 Module
Xin hỏi trong 2 cách trên thì cách nào thuận tiện hơn.
- Vòng lập duyệt từ trên xuốngBài toán này trông thế mà phức tạp gớm
Những dòng khai báo trên thì không vấn đề gì, nhưng đến công thức mấu chốt nhất của bài thì phức tạp đây (hình dung mãi nhưng chưa hiểu lắm)
ArrKQ(nR, nC) = ArrKQ(nR, nC) + Arr(i, 3)
Nhờ các pác giải thích dùm công thức trên, cho tôi hình dung cụ thể khi sau khi i chạy đến 12 (tức chạy đến Ô A13) thì ArrKQ(nR,nC)=Arr(2,2) chăng ?
(nR và iR hình như là một tức nR=ỉR? nhưng hình như không phải)
Nhờ các pác giải thích dùm công thức trên, cho tôi hình dung cụ thể khi sau khi i chạy đến 12 (tức chạy đến Ô A13) thì ArrKQ(nR,nC)=Arr(2,2) chăng ? (nR và iR hình như là một tức nR=ỉR? nhưng hình như không phải)
Vì code của bác ấy có dùng thuộc tính End(xlUP), mục đích xác định dòng cuối cùng có dữ liệu... Và cái thằng End(xlUP) này sẽ bị sai khi sheet đang có AutoFilterBác Thu Nghi giải thích giúp
With Sheets("Data")
.AutoFilterMode = False
có tác dụng gì thế? Tại sao cần dùng đến nó hả bác
Theo kinh nghiệm tối ưu hóa code thì việc so sánh số lượng kí tự trong chuỗi sẽ nhanh hơn là so sánh trực tiếp chuỗi đó, tức là nếu bạn so sánh giữa Len(a)=0 và a="" thì Len(a)=0 sẽ nhanh hơn.Xin thày Ndu giải thích hộ đoạn If Len(CStr(Arr(i, 1))) > 0 Then tại sao không dùng là If Arr(i, 1) <> "" Then vừa đơn giản, máy đỡ phải chuyển đổi >> nhanh hơn.
Sub Tonghop()
Dim DL(), eR As Long, i As Long, j As Long, Tmp1, Tmp2, Dong, Cot
With Sheets("Sheet1")
eR = .[C65000].End(xlUp).Row
DL = .Range("A2:C" & eR).Value
ReDim KQ(1 To UBound(DL, 1) + 1, 1 To UBound(DL, 1) + 1)
Set Dic1 = CreateObject("Scripting.Dictionary")
Set Dic2 = CreateObject("Scripting.Dictionary")
n = 1
m = 1
For i = 1 To UBound(DL, 1)
If DL(i, 1) <> "" Then
Tmp1 = DL(i, 1)
If Not Dic1.Exists(Tmp1) Then
n = n + 1
Dic1.Add Tmp1, n
Dong = Dic1.Item(Tmp1)
KQ(n, 1) = Tmp1
If DL(i, 2) <> "" Then
Tmp2 = DL(i, 2)
If Not Dic2.Exists(Tmp2) Then
m = m + 1
Dic2.Add Tmp2, m
Cot = Dic2.Item(Tmp2)
KQ(1, m) = Tmp2
KQ(Dong, Cot) = KQ(Dong, Cot) + DL(i, 3)
End If
End If
End If
End If
Next
End With
With Sheets("Sheet2")
.Cells.ClearContents
.[A1].Resize(Dong, Cot).Value = KQ
End With
End Sub
Sai quá trời luôn!Do chưa có kinh nghiệm, sau khi viết Code khi chạy vẫn ra kết quả nhưng tổng hợp không đúng, phiền mọi người xem hộ tôi, chỉ tôi nhầm ở đâu.
PHP:Sub Tonghop() Dim DL(), eR As Long, i As Long, j As Long, Tmp1, Tmp2, Dong, Cot With Sheets("Sheet1") eR = .[C65000].End(xlUp).Row DL = .Range("A2:C" & eR).Value ReDim KQ(1 To UBound(DL, 1) + 1, 1 To UBound(DL, 1) + 1) Set Dic1 = CreateObject("Scripting.Dictionary") Set Dic2 = CreateObject("Scripting.Dictionary") n = 1 m = 1 For i = 1 To UBound(DL, 1) If DL(i, 1) <> "" Then Tmp1 = DL(i, 1) If Not Dic1.Exists(Tmp1) Then n = n + 1 Dic1.Add Tmp1, n Dong = Dic1.Item(Tmp1) KQ(n, 1) = Tmp1 If DL(i, 2) <> "" Then Tmp2 = DL(i, 2) If Not Dic2.Exists(Tmp2) Then m = m + 1 Dic2.Add Tmp2, m Cot = Dic2.Item(Tmp2) KQ(1, m) = Tmp2 KQ(Dong, Cot) = KQ(Dong, Cot) + DL(i, 3) End If End If End If End If Next End With With Sheets("Sheet2") .Cells.ClearContents .[A1].Resize(Dong, Cot).Value = KQ End With End Sub
Sub Tonghop()
Dim DL, eR As Long, i As Long, n As Long, m As Long, Tmp1, Tmp2, Dong, Cot
Dim Dic1 As Object, Dic2 As Object, KQ()
With Sheets("Sheet1")
DL = .Range(.[A2], .[C65000].End(xlUp)).Value
End With
ReDim KQ(1 To UBound(DL, 1), 1 To UBound(DL, 1))
Set Dic1 = CreateObject("Scripting.Dictionary")
Set Dic2 = CreateObject("Scripting.Dictionary")
n = 1
m = 1
For i = 1 To UBound(DL, 1)
If DL(i, 1) <> "" And DL(i, 2) <> "" Then
Tmp1 = DL(i, 1)
If Not Dic1.Exists(Tmp1) Then
n = n + 1
Dic1.Add Tmp1, n
KQ(n, 1) = Tmp1
End If
Tmp2 = DL(i, 2)
If Not Dic2.Exists(Tmp2) Then
m = m + 1
Dic2.Add Tmp2, m
KQ(1, m) = Tmp2
End If
Dong = Dic1.Item(Tmp1)
Cot = Dic2.Item(Tmp2)
KQ(Dong, Cot) = KQ(Dong, Cot) + DL(i, 3)
End If
Next
With Sheets("Sheet2")
.Cells.ClearContents
.[A1].Resize(Dong, Cot).Value = KQ
End With
End Sub
Ah.. sơ ý!Code của thày chạy ra nó vẫn không được kết quả Sản phẩm 3 (chỉ ra sản phẩm 1 và 2) thôi.
Bản thân tôi cứ tưởng có 4 If thì có 4 End If là được, 4 End If này đặt đâu cũng thế vì không thấy lỗi.
Sub Tonghop()
Dim DL, eR As Long, i As Long, n As Long, m As Long, Tmp1, Tmp2, Dong, Cot
Dim Dic1 As Object, Dic2 As Object, KQ()
With Sheets("Sheet1")
DL = .Range(.[A2], .[C65000].End(xlUp)).Value
End With
ReDim KQ(1 To UBound(DL, 1), 1 To UBound(DL, 1))
Set Dic1 = CreateObject("Scripting.Dictionary")
Set Dic2 = CreateObject("Scripting.Dictionary")
n = 1
m = 1
For i = 1 To UBound(DL, 1)
If DL(i, 1) <> "" And DL(i, 2) <> "" Then
Tmp1 = DL(i, 1)
If Not Dic1.Exists(Tmp1) Then
n = n + 1
Dic1.Add Tmp1, n
KQ(n, 1) = Tmp1
End If
Tmp2 = DL(i, 2)
If Not Dic2.Exists(Tmp2) Then
m = m + 1
Dic2.Add Tmp2, m
KQ(1, m) = Tmp2
End If
Dong = Dic1.Item(Tmp1)
Cot = Dic2.Item(Tmp2)
KQ(Dong, Cot) = KQ(Dong, Cot) + DL(i, 3)
End If
Next
With Sheets("Sheet2")
.Cells.ClearContents
.[A1].Resize(m, n).Value = KQ
End With
End Sub
Sub Tonghop()
Dim DL, eR As Long, i As Long, n As Long, m As Long, Tmp1, Tmp2, Dong, Cot
Dim Dic1 As Object, Dic2 As Object, KQ()
With Sheets("Sheet1")
DL = .Range(.[A2], .[C65000].End(xlUp)).Value
End With
ReDim KQ(1 To UBound(DL, 1), 1 To UBound(DL, 1))
Set Dic1 = CreateObject("Scripting.Dictionary")
Set Dic2 = CreateObject("Scripting.Dictionary")
n = 1
m = 1
For i = 1 To UBound(DL, 1)
If DL(i, 1) <> "" And DL(i, 2) <> "" Then
Tmp1 = DL(i, 1)
If Not Dic1.Exists(Tmp1) Then
n = n + 1
Dic1.Add Tmp1, n
Dong = Dic1.Item(Tmp1)
KQ(n, 1) = Tmp1
End If
Tmp2 = DL(i, 2)
If Not Dic2.Exists(Tmp2) Then
m = m + 1
Dic2.Add Tmp2, m
Cot = Dic2.Item(Tmp2)
KQ(1, m) = Tmp2
End If
KQ(Dong, Cot) = KQ(Dong, Cot) + DL(i, 3)
End If
Next
With Sheets("Sheet2")
.Cells.ClearContents
.[A1].Resize(m, n).Value = KQ
End With
End Sub
Dong = Dic1.Item(Tmp1)
Cot = Dic2.Item(Tmp2)
- Khi bạn duyệt qua vòng lập từ trên xuống, bạn Add từng cái tmp1 vào Dic1 và tmp2 vào Dic2, đúng không?Ghi chú: 2 Code trên khác nhau là do thứ tự đặt 2 lệnh vị trí khác nhau
nhưng chưa hình dung được khi hoạt động thì nó khác nhau như thế nào nhỉ?PHP:Dong = Dic1.Item(Tmp1) Cot = Dic2.Item(Tmp2)
KQ muốn cộng dồn được thì phải xác định Dong, Cot trước, đúng không? Vì KQ(Dong, Cot) = KQ(Dong, Cot) + DL(i, 3)Vâng vâng, chỗ này có khi tôi chưa hiểu lắm về Dic thì phải, nhất trí KQ phải cộng sau End If rồi, nhưng Dong và Cot có thể đã xác định trước End If cũng được chứ hả bác.
Xin bác hộ cho tôi hiểu chỗ này với.
If Not Dic2.Exists(Tmp2) Then
m = m + 1
Dic2.Add Tmp2, m
KQ(1, m) = Tmp2
Cot = Dic2.Item(Tmp2)
End If
If Not Dic2.Exists(Tmp2) Then
m = m + 1
Dic2.Add Tmp2, m
KQ(1, m) = Tmp2
End If
Cot = Dic2.Item(Tmp2)
If Not Dic2.Exists(Tmp2) Then
m = m + 1
Dic2.Add Tmp2, m
KQ(1, m) = Tmp2
End If
Cot = Dic2.Item(Tmp2)
If Not Dic2.Exists(Tmp2) Then
m = m + 1
Dic2.Add Tmp2, m
KQ(1, m) = Tmp2
Cot = Dic2.Item(Tmp2)
End If
Thế thì 2 cách viết như sau là hoàn toàn khác nhau hả bác. Tôi cứ tưởng nó giống nhau chứ
PHP:If Not Dic2.Exists(Tmp2) Then m = m + 1 Dic2.Add Tmp2, m KQ(1, m) = Tmp2 Cot = Dic2.Item(Tmp2) End If
và cách viết
PHP:If Not Dic2.Exists(Tmp2) Then m = m + 1 Dic2.Add Tmp2, m KQ(1, m) = Tmp2 End If Cot = Dic2.Item(Tmp2)
Giải thích như bác kyo là chuẩn, dễ hiểu quá rồi.