Nhờ góp ý và thu gọn code tính điểm. (1 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

Ba Tê

Cạo Rồi Khỏi Gội
Tham gia
5/5/09
Bài viết
12,124
Được thích
17,588
Giới tính
Nam
Tôi vừa xem được quyển "Lập trình VBA trong Excel", thử viết thử một SUB, rất mong các Bạn "kỳ cựu VBA" rút gọn lại cho tối ưu nhất.
Thêm nữa, nhờ các Bạn góp ý: Nếu Bảng tính này có khoảng 15 sheet như thế, mỗi sheet là một môn, mỗi sheet khoảng 2500-3000 dòng thì có cách nào "tốt" nhất không, nhờ các Bạn góp ý - Đây chỉ là ý tưởng, mọi góp ý xây dựng ý tưởng đều rất trân trọng, không ngại phá bỏ biểu mẫu có sẵn.
Thành thật cảm ơn các Bạn!
-----------
Tôi nghĩ đây là chuyện tính điểm của GD, nếu sai Box, xin BQT chuyển đến vị trí thích hợp, thành thật cảm ơn.
Ba Tê.
 

File đính kèm

Lần chỉnh sửa cuối:
Ba Tê thử kiểm tra macro này xem sao

PHP:
Option Explicit
Public Sub GPE()
Dim Dong, myCount As Long
Dim MyRange As Range, Sh As Worksheet, Rng As Range

Application.ScreenUpdating = False
Set Sh = Worksheets("Toan")
Set MyRange = Worksheets("Toan").Range("A5:A2000")
With Application.WorksheetFunction
   myCount = .CountA(MyRange)
   Dong = 5
   Do While Dong <= myCount + 5
'- - - - - - - - - - - - Tinh Diem TB Hoc Ky 1'
      Set Rng = Sh.Range("F" & Dong & ":Q" & Dong)
      If .Count(Rng) = 0 Then
         Sh.Range("AD" & Dong) = ""
      Else
         Sh.Range("AD" & Dong) = Round(.Average(Rng, _
            Sh.Range("L" & Dong & ":Q" & Dong), Sh.Range("Q" & Dong)), 1)
      End If
'- - - - - - - - - - - - Tinh Diem TB Hoc Ky 2'
      Set Rng = Sh.Range("R" & Dong & ":AC" & Dong)
      If .Count(Rng) = 0 Then
         Sh.Range("AE" & Dong) = ""
      Else
         Sh.Range("AE" & Dong) = Round(.Average(Rng, _
            Sh.Range("X" & Dong & ":AC" & Dong), Sh.Range("AC" & Dong)), 1)
      End If
'- - - - - - - - - - - - Tinh Diem TB Ca Nam'
      If Sh.Range("AD" & Dong) = "" Or Sh.Range("AE" & Dong) = "" Then
         Sh.Range("AF" & Dong) = ""
      Else
         Sh.Range("AF" & Dong) = Round(((Sh.Range("AE" & Dong) * 2) + Sh.Range("AD" & Dong)) / 3, 1)
      End If
'- - - - - - - - - - - -'
      Dong = Dong + 1
   Loop
End With
Application.ScreenUpdating = True
End Sub

Ngoài ra ta còn thấy cách tính điểm HK I & HK II tương tợ nhau. Đã vậy ta có thể ghi ra 1 macro riêng & cung cấp cho macro này các tham số vùng ô tính cần thiết. (Tất nhiên, chuyện này chỉ mang tính học thuật)

Mệnh đề kiểu này
PHP:
Sh.Range("L" & Dong & ":Q" & Dong)
trong các câu lệnh có thể thay bằng Sh.Cells(Dong,"L").Resize(,6)
Nhưng fương thức Resize(x,y) ta từ từ rồi sẽ nhừ sau!

Chúc thành công.
 
Thấy cần fải hướng Ba Tê sang đường khác, an toàn hơn: Đó là hàm tự tạo

PHP:
Option Explicit
Function DiemHK(HS1 As Range, HS2 As Range, Optional Thi As Range, Optional HKy As Boolean = True)
 Dim Rng As Range
 
 If HKy Then
   Set Rng = Union(HS1, HS2, Thi)
   With Application.WorksheetFunction
      If .Count(Rng) > 0 Then _
         DiemHK = Round(.Average(Rng, Union(HS2, Thi), Thi), 1)
   End With
 Else
   If HS1.Value = "" Or HS2.Value = "" Then
      DiemHK = ""
   Else
      DiemHK = Round((2 * HS2.Value + HS1.Value) / 3, 1)
   End If
 End If
End Function


Cú fáp dùng hàm để tính điểm học kì I là: =diemHK(F5:K5,L5:P5,Q5) (cho em HS đang ở dòng 5)

Cú fáp dùng hàm để tính điểm học kì II là: =diemHK(R5:W5,X5:AB5,AC5) (cho em HS đang ở dòng 5)

& cuối cùng tính điểm trung bình cả năm của em í cú fáp sẽ là: =diemHK(AD5,AE5,,FALSE) (Chú í tìm hiểu chỗ được tô đỏ nha!)

Sao nói an toàn hơn: Vì khi sửa điểm trong bảng, hàm sẽ được cập nhật số liệu Automatic, khỏi quên hỉ!
 

File đính kèm

Tôi vừa xem được quyển "Lập trình VBA trong Excel", thử viết thử một SUB, rất mong các Bạn "kỳ cựu VBA" rút gọn lại cho tối ưu nhất.
Thêm nữa, nhờ các Bạn góp ý: Nếu Bảng tính này có khoảng 15 sheet như thế, mỗi sheet là một môn, mỗi sheet khoảng 2500-3000 dòng thì có cách nào "tốt" nhất không, nhờ các Bạn góp ý - Đây chỉ là ý tưởng, mọi góp ý xây dựng ý tưởng đều rất trân trọng, không ngại phá bỏ biểu mẫu có sẵn.
Thành thật cảm ơn các Bạn!
-----------
Anh có thể cho em biết các môn còn lại cấu trúc sh có giống như môn toán? Nếu giống như vậy em nghĩ rằng code của anh là khá chuẩn rồi. Lúc này em thích dùng vòng lặp và dùng WorksheetFunction thấy nhanh hơn
Range(...).FormulaR1C1
Hay Anh dùng Sub kết hợp UDF của Bác Sa cũng OK.
Để em dùng code của Anh gán vào array thử nhé, xem có nhanh hơn.
Anh dùng thử code sau thử, ok thì bỏ dòng tính time. Có lập sẵn để anh triển khai nhiều sh.
PHP:
Option Explicit
Option Base 1
Dim nDong As Long, endR As Long, k As Long
Dim iMon As Long
Dim shName As String
Dim WF As WorksheetFunction
Dim HS1 As Range, HS2 As Range, Thi As Range
Const fR As Long = 5
Sub TinhDiem()
Dim Arr() As Variant
Dim MonArr
Dim t As Variant
t = Timer
MonArr = Array("Toan", "Van", "Ly")
Set WF = WorksheetFunction
With Application
  .ScreenUpdating = False: .Calculation = xlCalculationManual
End With
'For iMon = 1 To 1 'UBound(MonArr)
  shName = MonArr(1)
  With Sheets(shName)
    endR = .Cells(65000, 1).End(xlUp).Row
    ReDim Arr(endR - fR + 1, 3)
    k = 1
    For nDong = 1 To endR - fR + 1
      'diem HK1'
      k = nDong + 4
      Set HS1 = .Range("F" & k & ":K" & k)
      Set HS2 = .Range("L" & k & ":P" & k)
      If WF.Count(HS1) = 0 Or WF.Count(HS2) = 0 Then
        Arr(nDong, 1) = ""
        Arr(nDong, 2) = ""
        Arr(nDong, 3) = ""
        GoTo bien
      End If
      Set Thi = .Range("Q" & k & ":Q" & nDong)
      Arr(nDong, 1) = DiemHK(HS1, HS2, Thi)
      'diem HK2'
      Set HS1 = .Range("R" & k & ":W" & k)
      Set HS2 = .Range("X" & k & ":AB" & k)
      If WF.Count(HS1) = 0 Or WF.Count(HS2) = 0 Then
        Arr(nDong, 1) = ""
        Arr(nDong, 2) = ""
        Arr(nDong, 3) = ""
        GoTo bien
      End If
      Set Thi = .Range("AC" & k & ":AC" & nDong)
      Arr(nDong, 2) = DiemHK(HS1, HS2, Thi)
      Arr(nDong, 3) = Round((2 * Arr(nDong, 1) + Arr(nDong, 2)) / 3, 1)
bien:
  Next nDong
    'gan vao'
    .Range("AD" & fR & ":AF" & endR) = Arr
    Cells(5, 34) = Timer - t
  End With
'Next iMon'
Set WF = Nothing
Set HS1 = Nothing
Set HS2 = Nothing
Set Thi = Nothing
With Application
  .ScreenUpdating = True: .Calculation = xlCalculationAutomatic
End With
End Sub
Function DiemHK(HS1 As Range, HS2 As Range, Optional Thi As Range)
Dim Rng As Range
Set Rng = Union(HS1, HS2, Thi)
DiemHK = Round(WF.Average(Rng, Union(HS2, Thi), Thi), 1)
Set Rng = Nothing
End Function
Anh test xem. cám ơn anh.
 
Lần chỉnh sửa cuối:
Anh có thể cho em biết các môn còn lại cấu trúc sh có giống như môn toán? Nếu giống như vậy em nghĩ rằng code của anh là khá chuẩn rồi. Lúc này em thích dùng vòng lặp và dùng WorksheetFunction thấy nhanh hơn
Range(...).FormulaR1C1
Hay Anh dùng Sub kết hợp UDF của Bác Sa cũng OK.
Để em dùng code của Anh gán vào array thử nhé, xem có nhanh hơn.
Anh dùng thử code sau thử, ok thì bỏ dòng tính time. Có lập sẵn để anh triển khai nhiều sh.
Anh test xem. cám ơn anh.
Tôi chưa hiểu cách dùng này, xin thông cảm vì mới chập chững vào VBA.
Ý tưởng của tôi là tạo khoảng 15 sheet, mỗi sheet là một môn học: Toán, Lý, Hóa, Sinh, Tin, Văn, Sử, Địa, Anh, GDCD, Công Nghệ, GDQP, Thể Dục, Tổng hợp, Thống kê... cho khoảng 40 lớp - 2000 học sinh.
Dùng hàm cho từng ô chắc máy sẽ chạy "cà giật" mỗi khi nhập liệu.
Tôi đang phân vân 3 cách: dùng Sub để tính mỗi sheet như sheet Toán hiện giờ, hay dùng Sub tính một loạt cả Worksheet, hay dùng hàm rồi làm Sub để khi mở tập tin thì chuyển máy tính sang chế độ Calculation manual, chỉ tính toán khi bấm vào một Command button, tính xong trở lại Calculation manual, đến khi đóng tập tin thì trả về Calculation Automatic, không biết cách nào là tốt nhất, nhờ các Bạn góp ý tiếp.
 

File đính kèm

Em gán code trên vào file, anh test lại nhé, chỉ cần nhấn nút "Tinh Diem" thì nó sẽ tính điểm TB 12 sh (12 môn).
Em dùng sub TinhDiem tính 1 lúc luôn cho khỏe.
Nếu các môn có số cột như nhau (cùng cấu trúc) thì dùng code trên, Còn nếu khác nhau thì em sẽ làm thêm 1 UDF để gán số cột.
 

File đính kèm

Lần chỉnh sửa cuối:
Em gán code trên vào file, anh test lại nhé, chỉ cần nhấn nút "Tinh Diem" thì nó sẽ tính điểm TB 12 sh (12 môn).
Em dùng sub TinhDiem tính 1 lúc luôn cho khỏe.
Nếu các môn có số cột như nhau (cùng cấu trúc) thì dùng code trên, Còn nếu khác nhau thì em sẽ làm thêm 1 UDF để gán số cột.
Đã biết cách làm rồi, Cảm ơn Bạn ThuNghi, nhưng do chưa hiểu rành lắm về cấu trúc các câu lệnh nên chưa chỉnh được, nhờ Bạn xem hộ tại sao các Học sinh này điểm số giống nhau nhưng kết quả lại khác nhau? Cảm ơn Bạn.
 

File đính kèm

Lần chỉnh sửa cuối:
Đã biết cách làm rồi, Cảm ơn Bạn ThuNghi, nhưng do chưa hiểu rành lắm về cấu trúc các câu lệnh nên chưa chỉnh được, nhờ Bạn xem hộ tại sao các Học sinh này điểm số giống nhau nhưng kết quả lại khác nhau? Cảm ơn Bạn.
Chờ em kiểm tra lại, chưa biết sai chỗ nào.
Em chạy lại mà kg thấy sai. Lúc đầu chạy thấy sai, em thử đónh excel và mở lại thì hết.
 

File đính kèm

Lần chỉnh sửa cuối:
Chờ em kiểm tra lại, chưa biết sai chỗ nào.
Em chạy lại mà kg thấy sai. Lúc đầu chạy thấy sai, em thử đónh excel và mở lại thì hết.
Điểm TB cả năm = (TB HK2*2 + TBHK1)/3, tôi đã chỉnh lại dòng này không biết có đúng không?
PHP:
Arr(nDong, 3) = Round((2 * Arr(nDong, 1) + Arr(nDong, 2)) / 3, 1)
thành:
Arr(nDong, 3) = Round((2 * Arr(nDong, 2) + Arr(nDong, 1)) / 3, 1)
Tôi cho chạy thử vẫn sai kết quả,
Mong Bạn kiểm tra tiếp.
 

File đính kèm

Lần chỉnh sửa cuối:
Điểm TB cả năm = (TB HK2*2 + TBHK1)/3, tôi đã chỉnh lại dòng này không biết có đúng không?
PHP:
Arr(nDong, 3) = Round((2 * Arr(nDong, 1) + Arr(nDong, 2)) / 3, 1)
thành:
Arr(nDong, 3) = Round((2 * Arr(nDong, 2) + Arr(nDong, 1)) / 3, 1)
Mong Bạn kiểm tra tiếp.
Đúng rồi Anh à,
Arr này có 3 cột: HK1, HK2, CN tương đương
Arr(nDong,i) i =1,2,3
Cái vụ array này em học trên GPE và nhờ Bác PTM gợi ý làm theo cách array để cải thiện tốc độ.
Em cũng thấy nó nhanh thật.
 
Đúng rồi Anh à,
Arr này có 3 cột: HK1, HK2, CN tương đương
Arr(nDong,i) i =1,2,3
Cái vụ array này em học trên GPE và nhờ Bác PTM gợi ý làm theo cách array để cải thiện tốc độ.
Em cũng thấy nó nhanh thật.
Nhờ Bạn xem lại dùm tập tin kèm ở bài #9, tôi thấy nó vẫn tính các Học sinh không giống nhau.
 
Nhờ Bạn xem lại dùm tập tin kèm ở bài #9, tôi thấy nó vẫn tính các Học sinh không giống nhau.
Xin lỗi anh nhiều, n1 sai có quy luật là 4 dòng, em tìm ra lý do là cl ở k và Ndong
Anh sửa đoạn sau trong code giúp em
Set Thi = .Range("Q" & k & ":Q" & nDong)
Thành
Tương tự
Set Thi = .Range("AC" & k & ":AC" & nDong)
thành
Vừa dư lại sai, do em sửa biên k mà quên.
 
Ổn rồi, thử mỗi sheet 2000 dòng, 13 sheet, chạy 2,6 giây, quá tuyệt.
Cảm ơn ThuNghi nhiều, còn phần sau mai mốt giúp tiếp nhé.
 
Lần chỉnh sửa cuối:
Ổn rồi, thử mỗi sheet 2000 dòng, 13 sheet, chạy 2,6 giây, quá tuyệt.
Cảm ơn ThuNghi nhiều, còn phần sau mai mốt giúp tiếp nhé.
Với dữ liệu được bố trí như file của bạn, tôi sẽ dùng code này:
PHP:
Sub TinhDiem(Diem As Range)
  Application.ScreenUpdating = False
  On Error Resume Next
  With Diem.Resize(, 1).Offset(, Diem.Columns.Count)
    .Resize(, 3).ClearContents
    .Offset(, 0).FormulaR1C1 = "=IF(COUNT(RC[-24]:RC[-13])=0,"""",ROUND(AVERAGE(RC[-24]:RC[-13],RC[-18]:RC[-13],RC[-13]),1))"
    .Offset(, 1).FormulaR1C1 = "=IF(COUNT(RC[-13]:RC[-2])=0,"""",ROUND(AVERAGE(RC[-13]:RC[-2],RC[-7]:RC[-2],RC[-2]),1))"
    .Offset(, 2).FormulaR1C1 = "=IF(OR(RC[-2]="""",RC[-1]=""""),"""",ROUND((RC[-2]+2*RC[-1])/3,1))"
    .Resize(, 3).Value = .Resize(, 3).Value
  End With
  Application.ScreenUpdating = True
End Sub
PHP:
Sub Main()
  Dim Sh As Worksheet, TG As Double
  TG = Timer
  For Each Sh In ThisWorkbook.Worksheets
    If Sh.Name <> "TK_CL" And Sh.Name <> "TONGHOP" Then
      TinhDiem Sh.Range("F5:AC5000")
    End If
  Next Sh
  MsgBox Timer - TG
End Sub
Chạy Sub Main để tính cho toàn bộ các sheet
Thử xem tổng thời gian là bao nhiêu nhé
----------------------------------
Với cách viết code như trên, bạn có thể tùy thích tính toán cho 1 sheet hay cho toàn bộ các sheet
 

File đính kèm

Lần chỉnh sửa cuối:
Với dữ liệu được bố trí như file của bạn, tôi sẽ dùng code này:
PHP:
Chạy Sub Main để tính cho toàn bộ các sheet
Thử xem tổng thời gian là bao nhiêu nhé
----------------------------------
Với cách viết code như trên, bạn có thể tùy thích tính toán cho 1 sheet hay cho toàn bộ các sheet[/QUOTE]
Mình đã gán 2 code vào chạy thử và nhận thấy dùng array có vẻ nhanh hơn.  NDU test giúp nhé.
Cơ bản tìm ra cách tối ưu mà.
 

File đính kèm

Mình đã gán 2 code vào chạy thử và nhận thấy dùng array có vẻ nhanh hơn. NDU test giúp nhé.
Cơ bản tìm ra cách tối ưu mà.
Cái này khỏi test cũng chắc như vậy rồi
Tôi cũng định làm nhưng.. hơi lười.. Ẹc.. Ẹc.. 2000 dòng dữ liệu ta dùng công thức rồi chuyển sang Value với mục đích cho code ngắn gọn thôi
Nói chung trong mọi trường hợp thì đặt kết quả tính toán vào 1 Array, sau khi xong việc ta gán Array này trở lại bảng tính là cách làm cho tốc độ nhanh nhất
(Có điều tôi nghĩ code của ThuNghi có thể rút gọn thêm được đấy)
 
Mình đã gán 2 code vào chạy thử và nhận thấy dùng array có vẻ nhanh hơn. NDU test giúp nhé.
Cơ bản tìm ra cách tối ưu mà.

Cái này khỏi test cũng chắc như vậy rồi
Tôi cũng định làm nhưng.. hơi lười.. Ẹc.. Ẹc.. 2000 dòng dữ liệu ta dùng công thức rồi chuyển sang Value với mục đích cho code ngắn gọn thôi
Nói chung trong mọi trường hợp thì đặt kết quả tính toán vào 1 Array, sau khi xong việc ta gán Array này trở lại bảng tính là cách làm cho tốc độ nhanh nhất
(Có điều tôi nghĩ code của ThuNghi có thể rút gọn thêm được đấy)

Cảm ơn các Bạn. Tôi đã test thử 12 sheet, xảy ra trường hợp sau:
Mỗi sheet có 51 dòng: code ThuNghi chạy 0.0625 - code ndu chạy 0.5477
Mỗi sheet có 2000 dòng: code ThuNghi chạy 2.625 - code ndu chạy 0.5631
Có đặc điểm nào đó mà số lượng dòng trong mỗi sheet tăng lên rất nhiều mà code của ndu tốc độ (thấy trong Msgbox) vẫn gần như tương đương, tôi không hiểu được, các Bạn nghiên cứu nhé.
 
Cảm ơn các Bạn. Tôi đã test thử 12 sheet, xảy ra trường hợp sau:
Mỗi sheet có 51 dòng: code ThuNghi chạy 0.0625 - code ndu chạy 0.5477
Mỗi sheet có 2000 dòng: code ThuNghi chạy 2.625 - code ndu chạy 0.5631
Có đặc điểm nào đó mà số lượng dòng trong mỗi sheet tăng lên rất nhiều mà code của ndu tốc độ (thấy trong Msgbox) vẫn gần như tương đương, tôi không hiểu được, các Bạn nghiên cứu nhé.
Sao lạ vậy nhỉ, thật sự code NDU nhanh hơn gần 10 lần với >2000 dòng.
Về logich thì thấy vô lý mà chưa nghĩ ra.
Cám ơn BaTê, cám ơn NDU.
 
Cảm ơn các Bạn. Tôi đã test thử 12 sheet, xảy ra trường hợp sau:
Mỗi sheet có 51 dòng: code ThuNghi chạy 0.0625 - code ndu chạy 0.5477
Mỗi sheet có 2000 dòng: code ThuNghi chạy 2.625 - code ndu chạy 0.5631
Có đặc điểm nào đó mà số lượng dòng trong mỗi sheet tăng lên rất nhiều mà code của ndu tốc độ (thấy trong Msgbox) vẫn gần như tương đương, tôi không hiểu được, các Bạn nghiên cứu nhé.
Tôi tin rằng cách dùng Array sẽ luôn cho kết quả nhanh hơn ---> Test code của ThuNghi, nếu cho kết quả chậm hơn thì có chăng là do code ấy chưa được tối ưu ở 1 công đoạn nào đó mà thôi
Tuy nhiên, dữ liệu của bạn cũng không phải là nhiều lắm, vì vậy bạn hoàn toàn có thể lựa chọn phương pháp của tôi (tốc độ tạm chấp nhận nhưng code gọn hơn và dễ hiểu hơn)
 
Nói chung trong mọi trường hợp thì đặt kết quả tính toán vào 1 Array, sau khi xong việc ta gán Array này trở lại bảng tính là cách làm cho tốc độ nhanh nhất
(Có điều tôi nghĩ code của ThuNghi có thể rút gọn thêm được đấy)
Tôi nghĩ không hẳn là như vậy. Như trường hợp test code của Ba Tê
Cảm ơn các Bạn. Tôi đã test thử 12 sheet, xảy ra trường hợp sau:
Mỗi sheet có 51 dòng: code ThuNghi chạy 0.0625 - code ndu chạy 0.5477
Mỗi sheet có 2000 dòng: code ThuNghi chạy 2.625 - code ndu chạy 0.5631
Có đặc điểm nào đó mà số lượng dòng trong mỗi sheet tăng lên rất nhiều mà code của ndu tốc độ (thấy trong Msgbox) vẫn gần như tương đương, tôi không hiểu được, các Bạn nghiên cứu nhé.
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.
 
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

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

Back
Top Bottom