Nhờ góp ý và thu gọn code tính điểm. (4 người xem)

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

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

Tôi nghĩ không hẳn là như vậy. Như trường hợp test code của Ba Tê

Tôi nghĩ nguyên nhân là như thế này:
Code của ThuNghi tính toán từng kết quả một và gán vào một Array. Sau khi tính hết sẽ gán kết quả của Array vào Vùng kết quả. Nếu dữ liệu ít thì cách này nhanh hơn. Nhưng nếu dữ liệu lớn, biến bạn dùng để lưu kết quả tạm (Là Array bạn dùng để lưu kết quả) sẽ chiếm tài nguyên nhiều hơn. Run code mà phải nhớ một biến có dung lượng càng lớn thì tốc độ của code sẽ càng chậm.
Vậy cùng làm 1 thí nghiệm đơn giản nhé
1> Dùng FormulaR1C1 rồi gán công thức thành Valule (không vòng lập)
PHP:
Sub Test1()
  Dim i As Long, TG As Double
  TG = Timer
  With Range("A1:A30000")
    .FormulaR1C1 = "=ROW()"
    .Value = .Value
  End With
  MsgBox Format(Timer - TG, "0.0000000000")
End Sub
2> Gán kết quả tính toán vào Array, cuối cùng gán Array vào vùng dữ liệu
PHP:
Sub Test2()
  Dim i As Long, TG As Double, Arr(1 To 30000, 1 To 1)
  TG = Timer
  For i = 1 To 30000
    Arr(i, 1) = i
  Next
  Range("B1:B30000") = Arr
  MsgBox Format(Timer - TG, "0.0000000000")
End Sub
Bạn thí nghiệm trên máy bạn xem cái nào nhanh hơn?
Tham khảo tiếp bài này: http://www.giaiphapexcel.com/forum/showthread.php?7146-Đố-vui-về-VBA!&p=240348#post240348
 
Lần chỉnh sửa cuối:
Vậy cùng làm 1 thí nghiệm đơn giản nhé
1> Dùng FormulaR1C1 rồi gán công thức thành Valule (không vòng lập)
PHP:
Sub Test1()
  Dim i As Long, TG As Double
  TG = Timer
  With Range("A1:A30000")
    .FormulaR1C1 = "=ROW()"
    .Value = .Value
  End With
  MsgBox Format(Timer - TG, "0.0000000000")
End Sub
2> Gán kết quả tính toán vào Array, cuối cùng gán Array vào vùng dữ liệu
PHP:
Sub Test2()
  Dim i As Long, TG As Double, Arr(1 To 30000, 1 To 1)
  TG = Timer
  For i = 1 To 30000
    Arr(i, 1) = i
  Next
  Range("B1:B30000") = Arr
  MsgBox Format(Timer - TG, "0.0000000000")
End Sub
Bạn thí nghiệm trên máy bạn xem cái nào nhanh hơn?
Tham khảo tiếp bài này: http://www.giaiphapexcel.com/forum/showthread.php?7146-Đố-vui-về-VBA!&p=240348#post240348
Hai code bạn đưa ra để thí nghiệm không thể nào so sánh với nhau được. Một code bạn phải dùng công thức(=ROW()), code còn lại bạn chỉ gán giá trị sẵn có (giá trị của i). Nếu bạn muốn thí nghiệm thì hãy thí nghiệm với 2 code sau, sẽ công bằng hơn.
PHP:
Sub Test1()
  Dim i As Long, TG As Double
  TG = Timer
  With Range("A1:A60000")
    .FormulaR1C1 = "=RC[2]*2"
    .Value = .Value
  End With
  MsgBox Format(Timer - TG, "0.0000000000")
End Sub
PHP:
Sub Test2()
  Dim i As Long, TG As Double, Arr(1 To 60000, 1 To 1)
  TG = Timer
  For i = 1 To 60000
    Arr(i, 1) = Cells(i, 3).Value * 2
  Next
  Range("B1:B60000") = Arr
  MsgBox Format(Timer - TG, "0.0000000000")
End Sub
Thay đổi độ rộng vùng dữ liệu. Ví dụ: 100 dòng, 200 dòng, 500 dòng, 1000 dòng, 2000 dòng, 5000 dòng, 10000 dòng, 20000 dòng, 50000 dòng.
Bạn sẽ thấy ban đầu, dữ liệu ít, dùng Array sẽ nhanh hơn. Nhưng càng mở rộng vùng dữ liệu thì sự chênh lệch về tốc độ càng giảm và đến một lúc nào đó code dùng công thức sẽ có tốc độ nhanh hơn. Và nếu tiếp tục mở rộng vùng dữ liệu thì sự chênh lệch về tốc độ sẽ tăng lên nhưng lúc này code dùng công thức là cái nhanh hơn.
 
Hai code bạn đưa ra để thí nghiệm không thể nào so sánh với nhau được. Một code bạn phải dùng công thức(=ROW()), code còn lại bạn chỉ gán giá trị sẵn có (giá trị của i). Nếu bạn muốn thí nghiệm thì hãy thí nghiệm với 2 code sau, sẽ công bằng hơn.
PHP:
Sub Test1()
  Dim i As Long, TG As Double
  TG = Timer
  With Range("A1:A60000")
    .FormulaR1C1 = "=RC[2]*2"
    .Value = .Value
  End With
  MsgBox Format(Timer - TG, "0.0000000000")
End Sub
PHP:
Sub Test2()
  Dim i As Long, TG As Double, Arr(1 To 60000, 1 To 1)
  TG = Timer
  For i = 1 To 60000
    Arr(i, 1) = Cells(i, 3).Value * 2
  Next
  Range("B1:B60000") = Arr
  MsgBox Format(Timer - TG, "0.0000000000")
End Sub
Thay đổi độ rộng vùng dữ liệu. Ví dụ: 100 dòng, 200 dòng, 500 dòng, 1000 dòng, 2000 dòng, 5000 dòng, 10000 dòng, 20000 dòng, 50000 dòng.
Bạn sẽ thấy ban đầu, dữ liệu ít, dùng Array sẽ nhanh hơn. Nhưng càng mở rộng vùng dữ liệu thì sự chênh lệch về tốc độ càng giảm và đến một lúc nào đó code dùng công thức sẽ có tốc độ nhanh hơn. Và nếu tiếp tục mở rộng vùng dữ liệu thì sự chênh lệch về tốc độ sẽ tăng lên nhưng lúc này code dùng công thức là cái nhanh hơn.
Bạn test rất hay!
Ẹc... Ẹc...
Nhưng khi viết code người ta ăn nhau ở thuật toán nữa
Nếu là tôi thì tôi sẽ viết vầy:
PHP:
Sub Test2()
  Dim i As Long, TG As Double, Arr(1 To 60000, 1 To 1), Tmp
  TG = Timer
  Tmp = Range("C1:C60000").Value
  For i = 1 To 60000
    Arr(i, 1) = Tmp(i, 1) * 2
  Next
  Range("B1:B60000") = Arr
  MsgBox Format(Timer - TG, "0.0000000000")
End Sub
Đố bạn làm 1 code khác nhanh hơn code này đấy!
(Chính vì thế mà tôi nhận xét rằng code của ThuNghi sở dĩ chậm là do chưa tối ưu chứ không phải dùng Array sẽ chậm hơn so với gán công thức đâu)
 

File đính kèm

Lần chỉnh sửa cuối:
(Chính vì thế mà tôi nhận xét rằng code của ThuNghi sở dĩ chậm là do chưa tối ưu chứ không phải dùng Array sẽ chậm hơn so với gán công thức đâu)
Tôi cũng thử đặt tmp=.range(.....) và xét theo for i mà cũng không nhanh hơn, chưa biết tối ưu chỗ nào nữa. Luẩn quẫn rồi, NDU tối ưu giúp nhé.
Cám ơn nhiều. Mình tin rằng arr sẽ nhanh hơn, vì đã từng dùng cho ex 2007 với 1.000.000 dòng rồi.
 
Bạn test rất hay!
Ẹc... Ẹc...
Nhưng khi viết code người ta ăn nhau ở thuật toán nữa
Nếu là tôi thì tôi sẽ viết vầy:
PHP:
Sub Test2()
  Dim i As Long, TG As Double, Arr(1 To 60000, 1 To 1), Tmp
  TG = Timer
  Tmp = Range("C1:C60000").Value
  For i = 1 To 60000
    Arr(i, 1) = Tmp(i, 1) * 2
  Next
  Range("B1:B60000") = Arr
  MsgBox Format(Timer - TG, "0.0000000000")
End Sub
Đố bạn làm 1 code khác nhanh hơn code này đấy!
(Chính vì thế mà tôi nhận xét rằng code của ThuNghi sở dĩ chậm là do chưa tối ưu chứ không phải dùng Array sẽ chậm hơn so với gán công thức đâu)
Ở đây, công thức tính toán quá đơn giản nên chưa thể thấy được sự khác biệt. Bây giờ chúng ta thử với một công thức phức tạp hơn. Mời bạn viết code dùng Array xem tốc độ có nhanh hơn cách dùng công thức hay không:
PHP:
Sub Test1()
  Dim i As Long, TG As Double
  TG = Timer
  With Range("C1:C60000")
    .FormulaR1C1 = "=VLOOKUP(RC[-1],Sheet2!R2C1:R11C8,MATCH(RC[-2],Sheet2!R1C1:R1C8,))"
    .Value = .Value
  End With
  MsgBox Format(Timer - TG, "0.0000000000")
End Sub
 

File đính kèm

Ở đây, công thức tính toán quá đơn giản nên chưa thể thấy được sự khác biệt. Bây giờ chúng ta thử với một công thức phức tạp hơn. Mời bạn viết code dùng Array xem tốc độ có nhanh hơn cách dùng công thức hay không:
PHP:
Sub Test1()
  Dim i As Long, TG As Double
  TG = Timer
  With Range("C1:C60000")
    .FormulaR1C1 = "=VLOOKUP(RC[-1],Sheet2!R2C1:R11C8,MATCH(RC[-2],Sheet2!R1C1:R1C8,))"
    .Value = .Value
  End With
  MsgBox Format(Timer - TG, "0.0000000000")
End Sub
Không phải công thức nào cũng có thể cho vào Array 1 cách hiệu quả. Tuy nhiên, với file của bạn thì.. có thể
PHP:
Sub Test2()
  Dim TG As Double, i As Long, SrcArray, SrcR, SrcC, FVal1, FVal2
  Dim Dic1, Dic2, Tmp As Long, Arr(1 To 60000, 1 To 1)
  TG = Timer
  Set Dic1 = CreateObject("Scripting.Dictionary")
  Set Dic2 = CreateObject("Scripting.Dictionary")
  FVal1 = Sheet1.Range("B1:B60000").Value
  FVal2 = Sheet1.Range("A1:A60000").Value
  SrcArray = Sheet2.Range("B2:H11").Value
  SrcR = Sheet2.Range("A2:A11").Value
  SrcC = Sheet2.Range("B1:H1").Value
  For i = 1 To UBound(SrcR, 1)
    Dic1.Add SrcR(i, 1), i
  Next
  For i = 1 To UBound(SrcC, 2)
    Dic2.Add SrcC(1, i), i
  Next
  For i = 1 To 60000
    Tmp = IIf(FVal1(i, 1) > 9, 9, Int(FVal1(i, 1)))
    Arr(i, 1) = SrcArray(Dic1.Item(Tmp), Dic2.Item(FVal2(i, 1)))
  Next
  Sheet1.Range("D1:D60000") = Arr
  Sheet1.[H2] = Format(Timer - TG, "0.00000000000")
End Sub
Hãy xem 3 vòng lập thi đấu với.. không vòng lập nha!
Và để biết được với dữ liệu lớn hơn nữa, Array sẽ hoạt động hiệu quả thế nào, bạn chạy code trên Excel 2007 với 1,048,576 dòng thì sẽ biết liền
PHP:
Sub Test2()
  Dim TG As Double, i As Long, SrcArray, SrcR, SrcC, FVal1, FVal2
  Dim Dic1, Dic2, Tmp As Long, Arr(1 To 1048576, 1 To 1)
  TG = Timer
  Set Dic1 = CreateObject("Scripting.Dictionary")
  Set Dic2 = CreateObject("Scripting.Dictionary")
  FVal1 = Sheet1.Range("B1:B1048576").Value
  FVal2 = Sheet1.Range("A1:A1048576").Value
  SrcArray = Sheet2.Range("B2:H11").Value
  SrcR = Sheet2.Range("A2:A11").Value
  SrcC = Sheet2.Range("B1:H1").Value
  For i = 1 To UBound(SrcR, 1)
    Dic1.Add SrcR(i, 1), i
  Next
  For i = 1 To UBound(SrcC, 2)
    Dic2.Add SrcC(1, i), i
  Next
  For i = 1 To 1048576
    Tmp = IIf(FVal1(i, 1) > 9, 9, Int(FVal1(i, 1)))
    Arr(i, 1) = SrcArray(Dic1.Item(Tmp), Dic2.Item(FVal2(i, 1)))
  Next
  Sheet1.Range("D1:D1048576") = Arr
  Sheet1.[H2] = Format(Timer - TG, "0.00000000000")
End Sub
Tôi đã thử nghiệm rất nhiều lần và có kết quả so sánh như sau:
- Code của bạn ra kết quả trong khoảng từ 7 đến 16 giây (chạy code lần đầu cho kết quả chậm nhất)
- Code của tôi luôn luôn ra kết quả = 6 giây (trong bất cứ lần chạy nào)
Vì dung lượng file khá lớn (14MB) nên tôi up lên trang mediafire. Các bạn download tại đây nhé
(Sao mình ghét cái font VNI đến thế cơ chứ)
---------------------------------------------------
Trở lại bài toán của Ba Tê:
- Sở dĩ tôi vẫn chưa bắt tay vào sửa code của ThuNghi là vì không biết phải xử lý hàm AVERAGE như thế nào trong mảng
 
Trở lại bài toán của Ba Tê:
- Sở dĩ tôi vẫn chưa bắt tay vào sửa code của ThuNghi là vì không biết phải xử lý hàm AVERAGE như thế nào trong mảng

Vì không có thì giờ nên chưa tham gia thảo luận mục này, tuy nhiên, nếu cải tiến Code Thu Nghi, tôi nghĩ thay vì dùng Average, ta dùng 2 vòng lặp: vòng 1 tính tổng HS1, vòng 2 tính tổng HS2*2, 2 kết quả đó cộng với Thi*3, rồi chia cho số đếm trong các lần tính tổng.

Thí dụ:

PHP:
For i = 1 to 6
    SumHS1 = SumHS1 + HS1(1, i)
    iCount1 = iCount1 + IIf(HS1(1, i) > 0, 1, 0)
Next

For i = 1 to 5
    SumHS2 = SumHS2 + HS1(1, i) * 2
    iCount2 = iCount2 + IIf(HS1(1, i) > 0, 2, 0)
Next

'Học kỳ 1,( hoặc học kỳ 2), dòng k'
Arr(k, 1) = (SumHS1 + SumHS2 + Thi (k, 1) * 3) / (iCount1 + iCount2 + IIf(Thi(k, 1) > 0, 3, 0) )

(Sao mình ghét cái font VNI đến thế cơ chứ)
Câu này nghe quen quen! (ghét ... đến thế)
 
Lần chỉnh sửa cuối:
Không phải công thức nào cũng có thể cho vào Array 1 cách hiệu quả. Tuy nhiên, với file của bạn thì.. có thể
- Sở dĩ tôi vẫn chưa bắt tay vào sửa code của ThuNghi là vì không biết phải xử lý hàm AVERAGE như thế nào trong mảng
Rất cám ơn NDU về code trên, học thêm 1 chiêu
Set Dic1 = CreateObject("Scripting.Dictionary")
Hay quá, vì mình đã từng dùng array vlookup khoản 1tr dòng trên ex2007 thấy tốc độ hơn nhiều. Do vậy mà bài toán của Batê mình thắc mắc là tại sao vậy thôi. NDU nhớ là bài của anh Batê còn thêm đoạn test nếu count(điểm HS1 và HS2) =0 => DTB="" <> =0.
Một lần nữa xin cám ơn những tranh luận hay và rất bổ ích về PP lập trình.

Bổ sung, hàm WF.Average sửa dụng với mảng OK mà.
HS1 = .Range("F" & k & ":Q" & k)
HS2 = .Range("L" & k & ":Q" & k)
Function DiemTB(HS1 As Variant, HS2 As Variant, Thi As Variant)
DiemTB = Round(WF.Average(HS1, HS2, Thi), 1)
End Function
 
Lần chỉnh sửa cuối:
Vì không có thì giờ nên chưa tham gia thảo luận mục này, tuy nhiên, nếu cải tiến Code Thu Nghi, tôi nghĩ thay vì dùng Average, ta dùng 2 vòng lặp: vòng 1 tính tổng HS1, vòng 2 tính tổng HS2*2, 2 kết quả đó cộng với Thi*3, rồi chia cho số đếm trong các lần tính tổng.

Thí dụ:

PHP:
For i = 1 to 6
    SumHS1 = SumHS1 + HS1(1, i)
    iCount1 = iCount1 + IIf(HS1(1, i) > 0, 1, 0)
Next

For i = 1 to 5
    SumHS2 = SumHS2 + HS1(1, i) * 2
    iCount2 = iCount2 + IIf(HS1(1, i) > 0, 2, 0)
Next

'Học kỳ 1,( hoặc học kỳ 2), dòng k'
Arr(k, 1) = (SumHS1 + SumHS2 + Thi (k, 1) * 3) / (iCount1 + iCount2 + IIf(Thi(k, 1) > 0, 3, 0) )
Sum và count trên Array vẫn được mà anh, em nghĩ là không cần phải duyệt qua hàng ngang. Vì mình phải tính đến việc mở rộng ra, lúc đó số lần HS1 và số lần HS2 của từng môn khác nhau nữa.
Em nghĩ rằng có thể trểin khai theo hướng sum(Arr)/Count(Arr) thế hàm WF.Average.
Hiện tại chưa nghĩ ra.
 
Rất cám ơn NDU về code trên, học thêm 1 chiêu
Hay quá, vì mình đã từng dùng array vlookup khoản 1tr dòng trên ex2007 thấy tốc độ hơn nhiều. Do vậy mà bài toán của Batê mình thắc mắc là tại sao vậy thôi. NDU nhớ là bài của anh Batê còn thêm đoạn test nếu count(điểm HS1 và HS2) =0 => DTB="" <> =0.
Một lần nữa xin cám ơn những tranh luận hay và rất bổ ích về PP lập trình.
Điều mà tôi rút kinh nghiệm với các bài thi đấu tốc độ ở trên là:
- Bằng mọi giá, phải chuyển dữ liệu trên bảng tính thành mảng
- Tính toán gì đó (nếu có) phải thực hiện trên các phần tử của mảng, không được tính theo giá trị của cell
- Bằng mọi giá, cố gắng hạn chế sử dụng các hàm của Excel (WorksheetFunction)... phải tính theo các cách mà mảng có thể thực hiện được ---> ví dụ thay vì INDEX hay VLOOPUP, ta dùng phương pháp truy xuất mảng kiểu SrcArray(i, j)... với i, j là vị trị ta tính toán ra sẳn ---> Vậy thay vì dùng hàm COUNT hay SUM thì nên dùng vòng lập, tự tính lấy giá trị iCount, iSum như sư phụ ptm0412 vừa nếu ở trên
---------------------
Còn những kinh nghiệm nào nữa, xin các cao thủ bổ sung thêm
 
Thử cải tiến Code ThuNghi, dùng toàn Array, có thể chưa tối ưu nhưng tốc độ đã cải thiện rất nhiều:
- Với 5000 dòng x 12 sheets: nhanh hơn code ndu: 3.65 so với 3.85. Trước đó là 35 giây.
- Với 10000 dòng x 12 sheets: chậm hơn: 7.85 giây so với code ndu: 5.78 giây
- Với 200 dòng x 12 sheet như ban đầu: 0.3125 giây, so với code ndu 1.2 giây
Mọi người test lại dùm, máy mình không tốt lắm.

Download here
 
Lần chỉnh sửa cuối:
Thử cải tiến Code ThuNghi, dùng toàn Array, có thể chưa tối ưu nhưng tốc độ đã cải thiện rất nhiều:
- Với 5000 dòng x 12 sheets: nhanh hơn code ndu: 3.65 so với 3.85. Trước đó là 35 giây.
- Với 10000 dòng x 12 sheets: chậm hơn: 7.85 giây so với code ndu: 5.78 giây

Mọi người test lại dùm, máy mình không tốt lắm.

Download here
Test trên máy em:
- Code ThuNghi ra kết quả trong 3.5 giây
- Code ndu ra kết quả trong 2.2 giây
Với bài này em e rằng dùng Array không thể nhanh hơn cách gán công thức ---> Không phải vì Array chậm hơn mà là do các phép tính quá phức tạp đã đẩy thời gian lên cao thêm!
Nói chung: Em vẫn luôn tin rằng cách dùng Array là tuyệt hảo nhất, với điều kiện nó tính toán được!
 
Cảm ơn tất cả các Bạn Sa_DQ, Ndu, Ptm0412, ThuNghi ... đã tham gia vào Topic này.
Như đã nói từ đầu, tôi chập chững học VBA, tự nghĩ ra một dữ liệu để học viết code, qua các Bạn tôi đã học hỏi được rất nhiều điều, có cái còn phải nghiên cứu thêm mới hiểu được vì nó quá sức hiểu của mình hiện giờ.
Tôi đã thử chạy các code của ThuNghi, ndu..., Ptm0412, mỗi cách thời gian mỗi khác.
Với dữ liệu mỗi sheet 2000 dòng thì:
ndu: 0.4375
Ptm412: 0.4843
ThuNghi: 2.6250
Việc phân tích để hiểu lý do, nguyên nhân các code chạy nhanh hay chậm thì tôi thua, các Bạn có lẽ sẽ hiểu được.
---------
Bây giờ nhờ các Bạn tiếp tục với sheet TK_CL, đây là ý tưởng tôi nghĩ ra để lọc dữ liệu, nếu có cách khác tiện lợi hơn thì các Bạn cứ thực hiện. Cách tính tôi nêu ra trong các comment của từng cột, Khi ta chọn điều kiện trong ô F2 và L2 thì sẽ có Bảng Thống kê chất lượng các môn như trên.
+ 13 môn, HK1, HK2, Cả năm tương đương 39 IF().
+ Danh sách các lớp và dòng tổng từng khối lớp, cộng chung toàn trường là tự động tạo ra khi chạy code.
+ Sheet Thể dục có cách tính riêng, tôi đã tính bằng công thức, nếu các Bạn hiểu được cách tính thì có thể viết dùm 1 Sub riêng cho môn Thể dục, nếu không có thời gian thì tạm để nó như thế, sẽ tính sau, cái cần bàn bây giờ là sheet TK_CL, khi xong sẽ đến sheet Tonghop.
Dữ liệu đã cắt bớt, mỗi sheet có 50 HS để giảm dung lượng, các Bạn giả định thêm vào cho đủ khoảng 2-3000HS, 38-40 lớp dùm nhé.
Mong các Bạn tiếp tục đề tài này, tôi rất ham học VBA.
Cảm ơn các bạn.
Ba Tê.
 

File đính kèm

Bây giờ nhờ các Bạn tiếp tục với sheet TK_CL, đây là ý tưởng tôi nghĩ ra để lọc dữ liệu, nếu có cách khác tiện lợi hơn thì các Bạn cứ thực hiện. Cách tính tôi nêu ra trong các comment của từng cột, Khi ta chọn điều kiện trong ô F2 và L2 thì sẽ có Bảng Thống kê chất lượng các môn như trên.
Tôi thấy nếu dùng công thức cũng đâu đến nỗi phức tạp lắm!
Ví dụ công thức cho cell B6
PHP:
=SUMPRODUCT((INDIRECT("'"&$F$2&"'!A5:A2000")=$A6)*(INDIRECT("'"&$F$2&"'!AD5:AD2000")>0))
Tương tự thế cho các cell khác
Nếu dùng code thì ngoài cách gán công thức còn có cách khác khá hay và nhanh gọn: AutoFilter ---> Cái này mình tôi bạn thừa sức (record macro)
 
Lần chỉnh sửa cuối:
Tôi thấy nếu dùng công thức cũng đâu đến nỗi phức tạp lắm!
Ví dụ công thức cho cell B6
PHP:
=SUMPRODUCT((INDIRECT("'"&$F$2&"'!A5:A2000")=$A6)*(INDIRECT("'"&$F$2&"'!AD5:AD2000")>0))
Tương tự thế cho các cell khác
Nếu dùng code thì ngoài cách gán công thức còn có cách khác khá hay và nhanh gọn: AutoFilter ---> Cái này mình tôi bạn thừa sức (record macro)
Công thức trên chỉ lấy dữ liệu theo môn(F2), còn một điều kiện của ô L2 nữa (Nếu L2 = HK1 thì lấy cột AD, L2 = HK2 thì lấy cột AE, Cả năm thì lấy cột AF - chưa kể đối với môn TD là các cột V,W,X) công thức sẽ quá dài lại là công thức mảng.
Với lại danh sách lớp, dòng cộng khối lớp, cộng toàn trường phải nhập bằng tay, nếu viết code chỉ cần 1 nút bấm sẽ tiện dụng hơn, Bạn gợi ý cách viết code đi.
 
Sao cái này mình kiểm tra trên máy mình thực hiện 3000 dòng thì kết quả như sau
là code của ptm0412: 0.078125
code của thunghi: 0.140625
code của ndu: 0.546875
chạy nhanh nhất là code của ptm0412 rồi đến thu Nghi cuối cùng là của ndu nhưng code của ndu thì ngắn nhất và dễ hiểu đọc nhất các bạn có thể giải thích thêm trong code được không vì mình không được học VBA nên chỉ biết sơ sơ thui mà máu thích nghiên cứu khổ một nỗi lả nó khó quá đọc không hiểu gì cả nên các bác giúp dịch giúp mình với nhé (Àh mà thấy code của ptm và Thu nghi hình như giống nhau nhưng sao tốc độ lại khác nhau thế kìa)
Cảm ơn tất cả các Bạn Sa_DQ, Ndu, Ptm0412, ThuNghi ... đã tham gia vào Topic này.
Như đã nói từ đầu, tôi chập chững học VBA, tự nghĩ ra một dữ liệu để học viết code, qua các Bạn tôi đã học hỏi được rất nhiều điều, có cái còn phải nghiên cứu thêm mới hiểu được vì nó quá sức hiểu của mình hiện giờ.
Tôi đã thử chạy các code của ThuNghi, ndu..., Ptm0412, mỗi cách thời gian mỗi khác.
Với dữ liệu mỗi sheet 2000 dòng thì:
ndu: 0.4375
Ptm412: 0.4843
ThuNghi: 2.6250
Việc phân tích để hiểu lý do, nguyên nhân các code chạy nhanh hay chậm thì tôi thua, các Bạn có lẽ sẽ hiểu được.
---------
Bây giờ nhờ các Bạn tiếp tục với sheet TK_CL, đây là ý tưởng tôi nghĩ ra để lọc dữ liệu, nếu có cách khác tiện lợi hơn thì các Bạn cứ thực hiện. Cách tính tôi nêu ra trong các comment của từng cột, Khi ta chọn điều kiện trong ô F2 và L2 thì sẽ có Bảng Thống kê chất lượng các môn như trên.
+ 13 môn, HK1, HK2, Cả năm tương đương 39 IF().
+ Danh sách các lớp và dòng tổng từng khối lớp, cộng chung toàn trường là tự động tạo ra khi chạy code.
+ Sheet Thể dục có cách tính riêng, tôi đã tính bằng công thức, nếu các Bạn hiểu được cách tính thì có thể viết dùm 1 Sub riêng cho môn Thể dục, nếu không có thời gian thì tạm để nó như thế, sẽ tính sau, cái cần bàn bây giờ là sheet TK_CL, khi xong sẽ đến sheet Tonghop.
Dữ liệu đã cắt bớt, mỗi sheet có 50 HS để giảm dung lượng, các Bạn giả định thêm vào cho đủ khoảng 2-3000HS, 38-40 lớp dùm nhé.
Mong các Bạn tiếp tục đề tài này, tôi rất ham học VBA.
Cảm ơn các bạn.
Ba Tê.
 
Lần chỉnh sửa cuối:
Tiếp bài #35 bên trên, sau 4 - 5 ngày tập viết code cho sheet TK_CL, dài lê thê nhưng chạy cũng được.
Như đã nói ở trên, đây chỉ là bài tập viết code để học hỏi thêm về VBA. Rất mong các Bạn hiểu biết nhiều về VBA góp ý, chỉnh sửa cho gọn lại, chạy nhanh hơn.
Xin cảm ơn các Bạn.
 

File đính kèm

Web KT

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

Back
Top Bottom