Tăng tốc VBA bằng mảng: Use 1 Array, Use 2 Arrays, Use 3 Arrays (1 người xem)

Liên hệ QC

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

Cá ngừ F1

( ͡° ͜ʖ ͡°)
Thành viên BQT
Moderator
Tham gia
1/1/08
Bài viết
2,579
Được thích
3,723
Donate (Momo)
Donate
Giới tính
Nam
Nghề nghiệp
Quan hệ.. và quan hệ..
Xin chào các anh/chị trên GPE,

- Căn cứ Topic "Hội thảo VBA trình độ 2: cho người đã học cơ bản"
- Theo đoạn Video tại bài #6 của sư phụ PTM

[video=youtube;aQtQiL2zVnE]https://www.youtube.com/watch?v=aQtQiL2zVnE&feature=youtu.be[/video]​

Em thấy có Use 1 Array, Use 2 Arrays, Use 3 Arrays: trong bài toán tính Doanh thu.
Quả thật là em chưa rõ về khái niệm này lắm: Dùng 1 mảng, 2 mảng, 3 mảng.
Em có làm 1 file tương tự, có sử dụng Code:

Mã:
Sub DoanhThu()


Dim i&, Arr(), KQ(), T As Double


T = Timer


Arr = Range(Sheet1.[B2], Sheet1.[C1000000].End(3))


    ReDim KQ(1 To UBound(Arr), 1 To 1)


    For i = 1 To UBound(Arr)


        KQ(i, 1) = Arr(i, 1) * Arr(i, 2)


    Next i


    Sheet1.[D2].Resize(i - 1, 1) = KQ


    MsgBox "SoDong " & i & " ThoiGian: " & Timer - T




End Sub

Em cũng ko biết code đó: Dùng 1 mảng, 2 mảng, 3 mảng...???

Vậy, mong anh/chị trên GPE chia sẻ những bài toán thực tế có thể áp dụng & kinh nghiệm về Dùng 1 mảng, 2 mảng, 3 mảng... để tăng tốc độ code

Em xin cảm ơn!
 

File đính kèm

Code trên là dùng 2 mảng 2 chiều. Xử lý trên mảng tương tự như xử lý trên range. Thường người ta dùng mảng để lưu giá trị thôi nên việc xử lý nhanh hơn range nhiều( range là một đối tượng chứa rất nhiều thuộc tính và phương thức, xử lý trên range rất cồng kền)
 
Upvote 0
Code trên là dùng 2 mảng 2 chiều. Xử lý trên mảng tương tự như xử lý trên range. Thường người ta dùng mảng để lưu giá trị thôi nên việc xử lý nhanh hơn range nhiều( range là một đối tượng chứa rất nhiều thuộc tính và phương thức, xử lý trên range rất cồng kền)
Cảm ơn bạn,
Vậy với bài toán trên dùng 3 mảng thì code như nào nhỉ?
 
Upvote 0
Theo ngu ý của mình có thể ý của thầy Mỹ là vầy:
- 1 mảng tức gôm tất cả các dữ liệu trên sheet vào 1 Array rồi xữ lý ( ví dụ như có 1 vùng gồm đơn giá, số lương thì đưa vùng này hết vào 1 mảng Array )
- 2 mảng tức đưa từng vùng( hoặc cột ) vào từng mảng ( ví dụ trên đưa đơn giá vào mảng đơn giá, đưa mảng số lượng vào mảng số lượng )
- Theo như gợi ý đường dẫn để tài mình post bên trên thì làm như cách đưa từng vùng vào từng mảng thì xử lý nó nhanh hơn !
 
Upvote 0
Cảm ơn bạn,
Vậy với bài toán trên dùng 3 mảng thì code như nào nhỉ?
Đoán đại. Đáp ứng được cái dùng 3 mảng, còn có tăng tốc hay không thì chả biết --=0
PHP:
Sub DoanhThu()
Const DongDau As Long = 2
Dim Mang1(), Mang2(), Mang3() As Double, DongCuoi As Long, Dong As Long, T As Double
T = Timer
DongCuoi = Cells(&H100000, 2).End(xlUp).Row
Mang1 = Range(Cells(DongDau, 2), Cells(DongCuoi, 2)).Value
Mang2 = Range(Cells(DongDau, 3), Cells(DongCuoi, 3)).Value
ReDim Mang3(1 To DongCuoi - DongDau + 1, 1 To 1)
For Dong = 1 To DongCuoi - DongDau + 1
    Mang3(Dong, 1) = Mang1(Dong, 1) * Mang2(Dong, 1)
Next
Range(Cells(DongDau, 4), Cells(DongCuoi, 4)).Value = Mang3
MsgBox "SoDong " & (Dong - 1) & " ThoiGian: " & Timer - T
End Sub
 
Upvote 0
Đoán đại. Đáp ứng được cái dùng 3 mảng, còn có tăng tốc hay không thì chả biết --=0
PHP:
Sub DoanhThu()
Const DongDau As Long = 2
Dim Mang1(), Mang2(), Mang3() As Double, DongCuoi As Long, Dong As Long, T As Double
T = Timer
DongCuoi = Cells(&H100000, 2).End(xlUp).Row
Mang1 = Range(Cells(DongDau, 2), Cells(DongCuoi, 2)).Value
Mang2 = Range(Cells(DongDau, 3), Cells(DongCuoi, 3)).Value
ReDim Mang3(1 To DongCuoi - DongDau + 1, 1 To 1)
For Dong = 1 To DongCuoi - DongDau + 1
    Mang3(Dong, 1) = Mang1(Dong, 1) * Mang2(Dong, 1)
Next
Range(Cells(DongDau, 4), Cells(DongCuoi, 4)).Value = Mang3
MsgBox "SoDong " & (Dong - 1) & " ThoiGian: " & Timer - T
End Sub
Tôi test thử thấy chậm hơn xíu xíu àh (thực ra chênh lệch ko đáng kể)...
 
Lần chỉnh sửa cuối:
Upvote 0
[video=youtube;RSwIwamJUPM]https://www.youtube.com/watch?v=RSwIwamJUPM&feature=youtu.be[/video]
 
Upvote 0
Là như vầy:

- Một mảng: là bao gồm cả 5 cột, cột 5 = cột 4 * cột 3, sau đó gắn lại cả mảng 5 cột xuống. Cách này chậm vì mảng lớn và không hay vì có khi người ta không muốn biến 4 cột đầu đang là công thức thành giá trị. Có thể cải tiến chỉ lấy 3 cột, cột 3 = cột 2 * cột 1, rồi gắn mảng 3 cột xuống, nhưng chỉ nhanh hơn 1 xíu. Đây là sự hao phí công sức gắn xuống.

- Hai mảng: Một mảng nguồn 2 cột và 1 mảng đích 1 cột. Khi gắn xuống chỉ gắn mảng đích (1 cột) nên nhanh hơn.

- 3 mảng: Trường hợp 2 cột cần nhân với nhau ở cách xa nhau (thí dụ cách nhau 3 cột), nếu gom cả 5 cột vào 1 mảng, nhân cột 1 và 5 thành mảng đích 1 cột thì lại hao phí bộ nhớ. Lúc này cần tách ra 2 mảng nguồn (mỗi mảng 1 cột) và 1 mảng đích 1 cột để tiết kiệm trở lại. Trong video clip, do vẫn không có cột nào xen vào giữa 2 cột nguồn nên không thấy sự tiết kiệm làm tăng tốc độ.

Do là lớp học bắt đầu về mảng, nên tôi phải giới thiệu tất cả các trường hợp, chứ không làm đùng 1 phát vô trường hợp tối ưu.
 
Upvote 0
Là như vầy:

- Một mảng: là bao gồm cả 5 cột, cột 5 = cột 4 * cột 3, sau đó gắn lại cả mảng 5 cột xuống. Cách này chậm vì mảng lớn và không hay vì có khi người ta không muốn biến 4 cột đầu đang là công thức thành giá trị. Có thể cải tiến chỉ lấy 3 cột, cột 3 = cột 2 * cột 1, rồi gắn mảng 3 cột xuống, nhưng chỉ nhanh hơn 1 xíu. Đây là sự hao phí công sức gắn xuống.

- Hai mảng: Một mảng nguồn 2 cột và 1 mảng đích 1 cột. Khi gắn xuống chỉ gắn mảng đích (1 cột) nên nhanh hơn.

- 3 mảng: Trường hợp 2 cột cần nhân với nhau ở cách xa nhau (thí dụ cách nhau 3 cột), nếu gom cả 5 cột vào 1 mảng, nhân cột 1 và 5 thành mảng đích 1 cột thì lại hao phí bộ nhớ. Lúc này cần tách ra 2 mảng nguồn (mỗi mảng 1 cột) và 1 mảng đích 1 cột để tiết kiệm trở lại. Trong video clip, do vẫn không có cột nào xen vào giữa 2 cột nguồn nên không thấy sự tiết kiệm làm tăng tốc độ.

Do là lớp học bắt đầu về mảng, nên tôi phải giới thiệu tất cả các trường hợp, chứ không làm đùng 1 phát vô trường hợp tối ưu.
Dạ. Cảm ơn sư phụ PTM, em đã hiểu, 1 phương pháp để tối ưu code.. Rất dễ hiểu ạh
ngoài ra, sư phụ PTM có thể cho vài bài áp dụng vào thực tế để ae GPE luyện code được ko ạ
em xin cảm ơn!!!
 
Upvote 0
Xem bài trích lọc này xem sao? ứng dụng để thống kê chi tiết từng cửa hàng
 

File đính kèm

Upvote 0
Xem bài trích lọc này xem sao? ứng dụng để thống kê chi tiết từng cửa hàng
Không biết file của bạn dùng font j mà lỗi, tôi không đọc được các dòng tiêu đề.
Với dữ liệu thế này, có lẽ dùng AF cũng là giải pháp tốt.
Cảm ơn bạn.
 
Upvote 0
Không biết file của bạn dùng font j mà lỗi, tôi không đọc được các dòng tiêu đề.
Với dữ liệu thế này, có lẽ dùng AF cũng là giải pháp tốt.
Cảm ơn bạn.
Nếu dữ liệu trên 10000 dòng bạn thử so sánh tốc độ 2 cách xem như thế nào? tùy từng trường hợp để ứng dụng để liệu cơm gắp mắm, mảng chỉ phát huy tác dụng nếu dữ liệu của bạn lớn, còn dữ liệu nhỏ thì chưa thấy gì đâu
 
Upvote 0
Đây là code vận dụng tối đa mảng của thầy,nhưng thầy khuyên là không nên dùng cách này vì không có tính tượng hình để mà sau này lỡ có sữa code thì khó hình dung lắm...bài này chỉ dùng 1 mảng duy nhất là ra kết quả !
Sub Amount()
Dim LastRw As Long, Arr()
t1 = Timer
LastRw = Sheet1.[a100000].End(xlUp).Row
Arr = Sheet1.Range("b2:c" & LastRw).Value
For i = 1 To UBound(Arr, 1)
Arr(i, 1) = Arr(i, 1) * Arr(i, 2)
Next i
Sheet1.Range("d2:d" & LastRw).Value = Arr
t2 = Timer
MsgBox t2 - t1
End Sub
 
Upvote 0
Dạ. Cảm ơn sư phụ PTM, em đã hiểu, 1 phương pháp để tối ưu code.. Rất dễ hiểu ạh
ngoài ra, sư phụ PTM có thể cho vài bài áp dụng vào thực tế để ae GPE luyện code được ko ạ
em xin cảm ơn!!!
Gởi cho bạn tham khảo một ứng dụng tiếp nữa, bạn xem cái này có dùng AF được không?
Ứng dụng tổng hợp tất cả các sheet Nhập vào 1 sheet tổng dùng Arr
Mã:
Sub Tong_HopNHAP(SH As Worksheet, ARR_D(), K As Long)
   Dim Arr_N()
   Dim I As Long
   Dim J As Long
   Dim DongCuoi As Long
   DongCuoi = SH.Range("A20000").End(xlUp).Row
   Arr_N = SH.Range("A6:I" & DongCuoi)
    For I = 1 To UBound(Arr_N, 1)
            K = K + 1
        For J = 1 To 9
            ARR_D(K, J) = Arr_N(I, J)
         Next J
   Next I
End Sub

Mã:
Sub MAIN02()
  Dim ARR_D(1 To 60000, 1 To 9)
  Dim K As Long
  K = 0
  Sheet40.Range("A6:Z10000").Clear
  Dim wkb As Workbook
  Set wkb = ThisWorkbook
For I = 1 To 34 Step 3
    Call Tong_HopNHAP(wkb.Worksheets(wkb.VBProject.VBComponents("Sheet" & I).Properties("Name").Value), ARR_D, K)
Next
Sheet40.Range("a6:Z10000").Clear
Sheet40.Range("a6").Resize(K, 9) = ARR_D
Sheet40.Range("a6").Resize(K, 9).Borders.LineStyle = 1
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Gởi cho bạn tham khảo một ứng dụng tiếp nữa, bạn xem cái này có dùng AF được không?
Ứng dụng tổng hợp tất cả các sheet Nhập vào 1 sheet tổng dùng Arr

muốn biết có AF được không thì phải biết trích lọc theo tiêu chí nào mới giao lưu được chứ ! file và code anh đưa lên hình như không lọc theo tiêu chỉ nào cả . cái nào cũng thêm zô vậy làm sao mà nói chuyện về AF được phải không nè
 
Upvote 0
Cái code đó là lấy tất cả các sheet dồn lại 1 sheet, nếu muốn dồn theo tiêu chí nào thì thêm cái if nữa là xong! Và sau khi thêm cái if đó nghĩ lại xem là AF có làm được như vậy không?
 
Upvote 0
Đây là code vận dụng tối đa mảng của thầy,nhưng thầy khuyên là không nên dùng cách này vì không có tính tượng hình để mà sau này lỡ có sữa code thì khó hình dung lắm...bài này chỉ dùng 1 mảng duy nhất là ra kết quả !

For i = 1 To UBound(Arr, 1)
Còn chỗ này nữa: Dùng 1 biến ghi nhận giá trị UBound, để khỏi tính UBound 1 tỷ lần
 
Upvote 0
Còn chỗ này nữa: Dùng 1 biến ghi nhận giá trị UBound, để khỏi tính UBound 1 tỷ lần
Câu này không đúng. Dòng lệnh đó chỉ thực thi 1 lần.
Chạy thử thủ tục này sẽ thấy:
PHP:
Sub Test()
Dim Arr(), i&
ReDim Arr(1 To 2)
For i = 1 To UBound(Arr, 1)
    ReDim Arr(1 To 10)
    Debug.Print i
Next
End Sub
 
Upvote 0
Câu này không đúng. Dòng lệnh đó chỉ thực thi 1 lần.
Nguyên lý làm việc của vòng lặp For Next là sau khi thực thi xong các câu lệnh bên trong, biến đếm i sẽ tăng 1 giá trị là step, sau đó so sánh với giá trị <To> để quyết dịnh chạy tiếp hay không. Giá trị <To> không phải là số, mà là UBound(), nên phải tính UBound() rồi mới so sánh được.

Câu lệnh Debug.Print i chỉ cho biết giá trị i trước khi vào next để tăng step, chứ không có ý nghĩa gì trong việc có tính UBound() hay không.
 
Lần chỉnh sửa cuối:
Upvote 0
Nguyên lý làm việc của vòng lặp For Next là sau khi thực thi xong các câu lệnh bên trong, biến đếm i sẽ tăng 1 giá trị là step, sau đó so sánh với giá trị <To> để quyết dịnh chạy tiếp hay không. Giá trị <To> không phải là số, mà là UBound(), nên phải tính UBound() rồi mới so sánh được.

Câu lệnh Debug.Print i chỉ cho biết giá trị i sau khi tăng step, chứ không có ý nghĩa gì trong việc có tính UBound() hay không.
Chưa chính xác, sau khi 1 câu lệnh được đặt ra, máy sẽ kiểm tra đầy đủ các điều kiện chưa, cấu trúc đúng chưa sau đó, nó sẽ tính trước, đại loại như thế này:

For i = 1 To UBound(Arr, 1)
....
Next


Giả sử UBound(Arr, 1)=100, Nó sẽ copy (biên dịch lại) vào một bộ nhớ tạm nào đó thành cái này:

For i = 1 To 100
....
Next


Rồi nó mới chạy.

Tôi luôn nghĩ nguyên tắc hoạt động của máy tính là như vậy.
 
Upvote 0
Hãy thử với vòng lặp 10 triệu lần.
Việc này đã được nói đến nhiều lần trước đây rồi.
Thử test với cái này:

Mã:
Sub test()
    Dim i As Long
    Dim Arr(1 To 10000000)
    Dim T As Double
    T = Timer()
    For i = 1 To 10000000
    
    Next
    MsgBox Timer - T
    T = Timer()
    For i = 1 To UBound(Arr)
    
    Next
    MsgBox Timer - T
End Sub

Hình như thời gian như nhau hoặc nếu có chậm cũng chả đáng kể.
 
Upvote 0
Nếu tách riêng 2 thủ tục, tôi thấy Ubound đôi khi còn nhanh hơn cả em kia nữa!

Mã:
Sub test()
    Dim i As Long
    Dim T As Double
    T = Timer()
    For i = 1 To 10000000
    
    Next
    MsgBox Timer - T
End Sub


Sub test1()
    Dim i As Long
    Dim Arr(1 To 10000000)
    Dim T As Double
    T = Timer()
    For i = 1 To UBound(Arr)
    
    Next
    MsgBox Timer - T
End Sub
 
Upvote 0
Tôi chỉ nói là mất công tính nhiều lần. Rõ ràng là VBA có tính lại vì:

Trong thủ tục của doveandrose:

Mã:
Public Sub demLan()
Dim r As Integer
For r = 1 To return10(r) Step 1
    
Next
End Sub

Hoặc bất kỳ thí dụ nào mà tham số <to> được tính từ biến đếm đang tăng, nếu không tính lại thì sao biết để so sánh? Nên nói rằng "Nó sẽ copy (biên dịch lại) vào một bộ nhớ tạm nào đó" (trở thành giá trị cố định) là không đúng.

Thử 10 triệu lần mà không làm gì trong mỗi vòng lặp thì cũng chưa biết ra sao, vì UBound() tính nhanh quá. Nhưng thử dùng 1 phép tính khác:
Giả định là vùng dữ liệu 100.000 dòng và 100 cột có số liệu là 0 toàn bộ.

Chạy thử 2 thủ tục sau:

PHP:
Sub Calc1()
Dim arr(1 To 100000, 1 To 100)
t = Timer
k = UBound(arr, 1): m = UBound(arr, 2)
For i = 1 To k
    For j = 1 To m
        arr(i, j) = 0
    Next
Next
'[A2].Resize(100000, 100) = arr'
[A1] = Timer - t

End Sub

Trước tiên chạy Calc1() 1 lần có dòng xanh xanh [A2].Resize(100000, 100) = arr để có số liệu. Sau đó vô hiệu dòng đó và So sánh với thủ tục sau:

PHP:
Sub Calc2()
Dim arr(1 To 100000, 1 To 100)
t = Timer
For i = 1 To ([A150000].End(xlUp).Row - 1)
    For j = 1 To [XX2].End(xlToLeft).Column
        arr(i, j) = 0
    Next
Next

[B1] = Timer - t

End Sub
 
Upvote 0
Tôi chỉ nói là mất công tính nhiều lần. Rõ ràng là VBA có tính lại vì:

Trong thủ tục của doveandrose:

Mã:
Public Sub demLan()
Dim r As Integer
For r = 1 To return10(r) Step 1
    
Next
End Sub

Hoặc bất kỳ thí dụ nào mà tham số <to> được tính từ biến đếm đang tăng, nếu không tính lại thì sao biết để so sánh? Nên nói rằng "Nó sẽ copy (biên dịch lại) vào một bộ nhớ tạm nào đó" (trở thành giá trị cố định) là không đúng.

Thử 10 triệu lần mà không làm gì trong mỗi vòng lặp thì cũng chưa biết ra sao, vì UBound() tính nhanh quá. Nhưng thử dùng 1 phép tính khác:
Giả định là vùng dữ liệu 100.000 dòng và 100 cột có số liệu là 0 toàn bộ.

Chạy thử 2 thủ tục sau:

PHP:
Sub Calc1()
Dim arr(1 To 100000, 1 To 100)
t = Timer
k = UBound(arr, 1): m = UBound(arr, 2)
For i = 1 To k
    For j = 1 To m
        arr(i, j) = 0
    Next
Next
'[A2].Resize(100000, 100) = arr'
[A1] = Timer - t

End Sub

Trước tiên chạy Calc1() 1 lần có dòng xanh xanh [A2].Resize(100000, 100) = arr để có số liệu. Sau đó vô hiệu dòng đó và So sánh với thủ tục sau:

PHP:
Sub Calc2()
Dim arr(1 To 100000, 1 To 100)
t = Timer
For i = 1 To ([A150000].End(xlUp).Row - 1)
    For j = 1 To [XX2].End(xlToLeft).Column
        arr(i, j) = 0
    Next
Next

[B1] = Timer - t

End Sub

Trời ơi, so thì phải so như thế này chứ?

Mã:
Sub Calc1()
Dim arr(1 To 100000, 1 To 100)
T = Timer
k = UBound(arr, 1): m = UBound(arr, 2)
For i = 1 To k
    For j = 1 To m
        arr(i, j) = 0
    Next
Next
[A1] = Timer - T
End Sub


Sub Calc2()
Dim arr(1 To 100000, 1 To 100)
T = Timer
For i = 1 To UBound(arr, 1)
    For j = 1 To UBound(arr, 2)
        arr(i, j) = 0
    Next
Next
[A2] = Timer - T
End Sub

Sub Calc3()
Dim arr(1 To 100000, 1 To 100)
T = Timer
For i = 1 To 100000
    For j = 1 To 100
        arr(i, j) = 0
    Next
Next
[A3] = Timer - T
End Sub

Chạy ô tô cũng đến, chạy xe đạp cũng đến, sao lấy ô tô lại so vận tốc của xe đạp?
 
Lần chỉnh sửa cuối:
Upvote 0
Trời ơi, so thì phải so như thế này chứ?


Chạy ô tô cũng đến, chạy xe đạp cũng đến, sao lấy ô tô lại so vận tốc của xe đạp?
Hai thủ tục vừa rồi có chứng minh được rằng UBound() chỉ tính 1 lần không tính lại không? Tôi không so tốc độ để hơn thua, tôi chỉ chứng minh rằng nếu <to> phải tính toán, mà không dùng biến ghi nhận giá trị <to>, thì <to> phải tính nhiều lần. Tính nhanh cũng phải tính nhiều lần. Nếu Nghĩa vẫn không thấy vấn đề, không nhớ mình đã nói những gì và phải chứng minh cái gì, thì tôi không viết thêm gì nữa. Sẵn đầu gối trước mặt tôi nói chuyện với nó.
 
Lần chỉnh sửa cuối:
Upvote 0
Hai thủ tục vừa rồi có chứng minh được rằng UBound() chỉ tính 1 lần không tính lại không? Tôi không so tốc độ để hơn thua, tôi chỉ chứng minh rằng nếu <to> phải tính toán, mà không dùng biến ghi nhận giá trị <to>, thì <to> phải tính nhiều lần. Tính nhanh cũng phải tính nhiều lần. Nếu Nghĩa vẫn không thấy vấn đề, không nhớ mình đã nói những gì và phải chứng minh cái gì, thì tôi không viết thêm gì nữa. Sẵn đầu gối trước mặt tôi nói chuyện với nó.
Đã từng trải nghiệm khi sử dụng gì đó trên Range đều chậm mà, muốn thử thì thử Range với Range chứ ai nào lại thử Ubound với Range chứ!+-+-+-+
 
Upvote 0
Hai thủ tục của tôi xài trên range thật. Kết quả 1 thủ tục 0.7 giây, 1 thủ tục 9.5 giây. Chả lẽ tính xlUp.Row 1 lần cộng với xlToLeft.Column 1 lần, mất 7.8 giây?

Vậy thì sửa thủ tục Calc1()

Mã:
[COLOR=#0000cd]k = ([A150000].End(xlUp).Row - 1): m = [XX2].End(xlToLeft).Column[/COLOR]
For i = 1 To k
    For j = 1 To m
Nhớ là sửa sau khi đã có số liệu 10 triệu con số 0
 
Lần chỉnh sửa cuối:
Upvote 0
Nói túm lại là For đầu nó chỉ tính 1 lần, các For trong được tính theo số lần lặp lại. Cho nên làm gì thì làm bên trong For nếu xử lý được dữ liệu càng cố định càng tốt, bớt tính toán trong For là ổn.

Hai thủ tục dưới đây đều ngang thời gian nhau, như vậy vòng lặp đầu, For chỉ tính có 1 lần (không phải tính 1 trăm ngàn lần như Lão Chết Tiệt tưởng):

Mã:
Sub Calc4()
Dim arr(1 To 100000, 1 To 100)
T = Timer
For i = 1 To ([b150000].End(xlUp).Row - 1)
    For j = 1 To [XX2].End(xlToLeft).Column - 1
        arr(i, j) = 0
    Next
Next
[a1] = Timer - T
End Sub


Sub Calc6()
Dim arr(1 To 100000, 1 To 100)
T = Timer
k = ([b150000].End(xlUp).Row - 1)
For i = 1 To k
    For j = 1 To [XX2].End(xlToLeft).Column - 1
        arr(i, j) = 0
    Next
Next
[a3] = Timer - T
End Sub
 
Upvote 0
Ban đầu thì Nghĩa nói thế này:
Giả sử UBound(Arr, 1)=100, Nó sẽ copy (biên dịch lại) vào một bộ nhớ tạm nào đó thành cái này:

For i = 1 To 100
....
Next


Rồi nó mới chạy.

Tôi luôn nghĩ nguyên tắc hoạt động của máy tính là như vậy.

Bây giờ lại có nguyên tắc hoạt động for ngoài copy và for trong không copy. Lát nữa còn nguyên tắc gì nữa không?

Bài 33 tôi có edit về việc sửa Calc1()

Mã:
[COLOR=#0000cd]k = ([A150000].End(xlUp).Row - 1): m = [XX2].End(xlToLeft).Column[/COLOR]
For i = 1 To k
    For j = 1 To m

Như vậy là đồng đều cả 2 thủ tục đều xài range. Bây giờ thấy lập luận "nhiều nguyên tắc hoạt động" nên tôi thôi. Lần này thôi thật.
 
Upvote 0
Vậy bài này nói gì đây? Chạy 1 tỷ lần hay 1 lần ở vòng lặp đầu? Tưởng hoài!

Từ đầu tới giờ tôi chỉ chứng minh chính điều đó. Nếu không dùng biến ghi nhận giá trị <to>, trong khi <to> phải tính toán, thì sẽ phải tính nhiều lần. Tính nhanh, tính chậm, đều phải tính nhiều lần.

Câu nói đó đang nói về 1 thủ tục cụ thể nên tôi nói UBound. Và bây giờ tôi vẫn nói UBound vẫn phải tính nhiều lần. Nhất quán, không có 2, 3, 4 nguyên tắc ba hồi 1 ba hồi nhiều.

Nguyên tắc của tôi và tôi muốn những người nghe tôi hướng dẫn trong lớp VBA làm theo, là phải khai báo biến và dùng biến ghi giá trị <to> nếu như <to> phải tính toán, dù cho tính nhanh hay tính chậm. Nếu không, thì từ 0.7 giây biến thành 9.5 giây cho 10 triệu lần lặp.

Bài này tôi viết cho những người khác đọc, và nên làm theo.
 
Upvote 0
Từ đầu tới giờ tôi chỉ chứng minh chính điều đó. Nếu không dùng biến ghi nhận giá trị <to>, trong khi <to> phải tính toán, thì sẽ phải tính nhiều lần. Tính nhanh, tính chậm, đều phải tính nhiều lần.

Câu nói đó đang nói về 1 thủ tục cụ thể nên tôi nói UBound. Và bây giờ tôi vẫn nói UBound vẫn phải tính nhiều lần. Nhất quán, không có 2, 3, 4 nguyên tắc ba hồi 1 ba hồi nhiều.

Nguyên tắc của tôi và tôi muốn những người nghe tôi hướng dẫn trong lớp VBA làm theo, là phải khai báo biến và dùng biến ghi giá trị <to> nếu như <to> phải tính toán, dù cho tính nhanh hay tính chậm. Nếu không, thì từ 0.7 giây biến thành 9.5 giây cho 10 triệu lần lặp.

Bài này tôi viết cho những người khác đọc, và nên làm theo.
Túm lại, nếu vòng lặp For chỉ 1 vòng, có tính 1 tỷ lần không hay tính 1 lần? Chỉ vậy thôi.
 
Upvote 0
Hỏi thừa. Câu trả lời là câu đầu tiên trong bài trích dẫn của câu hỏi.
 
Upvote 0
Hỏi thừa. Câu trả lời là câu đầu tiên trong bài trích dẫn của câu hỏi.
bài #34 giải thích quá đúng về lý do 2 sub của thầy PTM có tốc độ khác nhau . Nhược bằng thầy PTM nhất định rằng mỗi vòng lặp nó sẽ tính toán lại biểu thức để so sánh biến lặp thì mời thầy dự đoán vòng lặp này sẽ chạy bao nhiêu lần khi cột A hoàn toàn trống trơn . thầy muốn ví dụ về Range thì em cũng xin dùng Range luôn
Mã:
Public Sub hello()
Dim r As Integer
With Sheet3
    For r = 1 To .[A1000000].End(xlUp).Row Step 1
        .Range("A" & .[A1000000].End(xlUp).Row + 1).Value = r
    Next
End With
End Sub
 
Upvote 0
em nghĩ rằng bản chất của vòng lặp kiểu <To> trong Visual Basic nó chỉ tính toán biểu thức sau <To> 1 lần duy nhất để làm đích đến . các vòng sau cứ nhắm cái đích này mà hướng đến chứ không tính toán lại cái đích đó nữa . Bởi đơn giản con số đằng sau <to> không được coi là 1 biểu thức điều kiện . mà chỉ được coi là 1 con số được chọn làm đích đến
không giống như bản chất vòng lặp While cứ mỗi vòng là phải tính toán biểu thức điều kiệu sau While trả về True mới cho lặp tiếp
đây cũng là bản chất của vòng lặp For nhưng là trong ngôn ngữ C
nếu bài #26 được viết lại trong môi trường C
Mã:
private void button1_Click(object sender, EventArgs e)
        {
            int i = 0;
            for (i = 1; i < return10();i++ )
            {


            }
        }
        private int return10()
        {
            MessageBox.Show("hello");
            return 10;
        }

thì hàm return10() sẽ được gọi 10 lần vì vòng For trong môi trường C phải tính toán lại biểu thức điều kiện giữa 2 dấu ;;
cho mỗi lần lặp
nhưng vb thì khác . kể cả là viết lại bài #26 trong môi trường VB.net thì hàm return10 () cũng chỉ được gọi 1 lần duy nhất mà thôi
 
Upvote 0
bài #34 giải thích quá đúng về lý do 2 sub của thầy PTM có tốc độ khác nhau .
Bạn biết code trong bài 34 của bạn nói nó tính End() bao nhiêu lần không?
Cả 2 thủ tục đều tính xlToLeft 10 triệu lần. Thủ tục Calc4 tính xlUp 100 ngàn lần, thụ tục Calc6 chỉ tính 1 lần cho biến k. 10 triệu so với 10 triệu 100 ngàn nên không thấy sự khác biệt lớn là phải rồi.

Ghi chú:
Theo lập luận nhất quán của tôi từ đầu đến cuối, mỗi lần next thì biến đếm tăng step, và so sánh với <to>. Nếu <to> cần phải tính thì sẽ tính. Vậy Next vòng lặp trong được gọi bao nhiêu lần? 10 triệu lần. Next vòng lặp ngoài được gọi 100 ngàn lần.

Nhược bằng thầy PTM nhất định rằng mỗi vòng lặp nó sẽ tính toán lại biểu thức để so sánh biến lặp thì mời thầy dự đoán vòng lặp này sẽ chạy bao nhiêu lần khi cột A hoàn toàn trống trơn . thầy muốn ví dụ về Range thì em cũng xin dùng Range luôn
Mã:
Public Sub hello()
Dim r As Integer
With Sheet3
    For r = 1 To .[A1000000].End(xlUp).Row Step 1
        .Range("A" & .[A1000000].End(xlUp).Row + 1).Value = r
    Next
End With
End Sub
Bạn nghĩ rằng tôi không biết for i = 1 to 1 step 1 thì chạy bao nhiêu lần à?
 
Upvote 0
Bạn biết code trong bài 34 của bạn nói nó tính End() bao nhiêu lần không?
Cả 2 thủ tục đều tính xlToLeft 10 triệu lần. Thủ tục Calc4 tính xlUp 100 ngàn lần, thụ tục Calc6 chỉ tính 1 lần cho biến k. 10 triệu so với 10 triệu 100 ngàn nên không thấy sự khác biệt lớn là phải rồi.

Ghi chú:
Theo lập luận nhất quán của tôi từ đầu đến cuối, mỗi lần next thì biến đếm tăng step, và so sánh với <to>. Nếu <to> cần phải tính thì sẽ tính. Vậy Next vòng lặp trong được gọi bao nhiêu lần? 10 triệu lần. Next vòng lặp ngoài được gọi 100 ngàn lần.


Bạn nghĩ rằng tôi không biết for i = 1 to 1 step 1 thì chạy bao nhiêu lần à?

thầy ghi for i = 1 to 1 step 1 có 2 khả năng xảy ra :
1 là thầy thừa nhận sau To đã là 1 hằng số không đổi và không cần tính lại trong suốt vòng lặp For
2 là thầy không hiểu câu lệnh này có nghĩa là gì
.Range("A" & .[A1000000].End(xlUp).Row + 1).Value = r
thầy muốn em nghĩ thầy trong trường hợp nào
em nhỏ tuổi lắm thầy ạ . ngày mà thầy lừng danh trên diễn đàn này chắc em còn đang bú mẹ
nhưng khổ cái tính em lỳ như trâu . người khác nói mà không có lý luận không thuyết phục thì em không tin cho dù người đó có nổi tiếng đến đâu .
 
Upvote 0
thầy ghi for i = 1 to 1 step 1 có 2 khả năng xảy ra :
1 là thầy thừa nhận sau To đã là 1 hằng số không đổi và không cần tính lại trong suốt vòng lặp For
Tôi không thừa nhận <to> là 1 số không đổi. Câu tôi viết có nghĩa rằng sau khi tính toán 1 lần đầu, <to> = 1.

Thế là for chạy vòng lặp đầu tiên. Ngay khi chạy Next lần 1, r tăng 1 thành 2, nó lại so sánh với [A1000000].End(xlUp).Row thấy lớn hơn và thoát luôn.

2 là thầy không hiểu câu lệnh này có nghĩa là gì
.Range("A" & .[A1000000].End(xlUp).Row + 1).Value = r
Tôi đã đọc và sợ rằng đọc sai nên đã chạy thử. Tôi chạy bằng F8 chứ không phải F5 nên tôi càng khẳng định vì câu lệnh đó chỉ được tô vàng có 1 lần. Sau đó sau khi gặp Next, r = 2 và thoát ra luôn.
 
Upvote 0
Tôi không thừa nhận <to> là 1 số không đổi. Câu tôi viết có nghĩa rằng sau khi tính toán 1 lần đầu, <to> = 1.

Thế là for chạy vòng lặp đầu tiên. Ngay khi chạy Next lần 1, r tăng 1 thành 2, nó lại so sánh với [A1000000].End(xlUp).Row thấy lớn hơn và thoát luôn.


Tôi đã đọc và sợ rằng đọc sai nên đã chạy thử. Tôi chạy bằng F8 chứ không phải F5 nên tôi càng khẳng định vì câu lệnh đó chỉ được tô vàng có 1 lần. Sau đó sau khi gặp Next, r = 2 và thoát ra luôn.

theo lý luận của thầy (không phải em) thì thầy vui lòng cho biết lý do sao r lại lớn hơn ?
để em diễn giải vòng lặp theo kịch bản của thầy
khi r = 1 sau <to> là biểu thức cần tính => .[A1000000].End(xlUp).Row = 1 hợp lệ => thực hiện lệnh bên trong
.Range("A" & .[A1000000].End(xlUp).Row + 1).Value = r
mà .[A1000000].End(xlUp).Row + 1 lúc này bằng 2 => .[A2] = 1 hết 1 vòng nhảy step 1 => r = 2

khi r = 2 sau <to> là biểu thức cần tính vì .[A2] = 1 => .[A1000000].End(xlUp).Row phải = 2
vậy xin thầy cho biết lý do tại sao r = 2 và .[A1000000].End(xlUp).Row = 2 mà phải Break vòng lặp ?
 
Upvote 0
thầy muốn em nghĩ thầy trong trường hợp nào
em nhỏ tuổi lắm thầy ạ . ngày mà thầy lừng danh trên diễn đàn này chắc em còn đang bú mẹ
nhưng khổ cái tính em lỳ như trâu . người khác nói mà không có lý luận không thuyết phục thì em không tin cho dù người đó có nổi tiếng đến đâu .
Có khi bạn phản biện đúng và chỉ ra chỗ sai của tôi cũng nên. Từ đầu đến giờ, HTN phản biện dở ẹt nên không phản bác được. Để tôi tóm tắt thế này:
- Tôi nói nếu không dùng biến ghi nhận UBound (trong trường hợp cụ thể đang dùng UBound() làm <to>), thì sẽ bị tính nhiều lần (tỷ lần, có phóng đại lên)
- HuuThangbd nói chỉ tính 1 lần và cho 1 thủ tục minh họa
- Tôi chỉ ra rằng câu lệnh Debug.Prict của Thắng chỉ cho biết giá trị của i trước khi gặp Next là bao nhiêu, chứ không chứng tỏ việc <to> có được tính hay không.
- HTN đưa 2 thủ tục chạy gần như nhau
- Tôi cho rằng UBound tính nhanh quá nên không thấy khác biệt, tôi đưa 2 thủ tục tính <to> bằng End(), sự khác biệt là rất lớn
- HTN phản biện rằng đã lấy UBound() so sánh với tính trên Range
- Tôi chấp nhận và sửa code cả 2 thủ tục đều tính trên Range, kết quả vẫn khác biệt rất lớn
- Bài 34, HTN đưa 2 thủ tục tính trên Range chạy như nhau, và cho rằng vòng lặp ngoài tính 1 lần, vòng lặp trong tính nhiều lần. Như vậy là không nhất quán với các bài ở trên, vì bài trên HTN khẳng định chỉ tính 1 lần.
- Bài 42, tôi tính lại cho thấy tại sao 2 thủ tục của Nghĩa chạy gần bằng nhau: Số lần tính của 2 thủ tục chỉ chênh nhau 1%.
- Bài 41, bạn đưa ra 1 thủ tục để hỏi (hay đố) mà không đưa ra lập luận gì sau khi chạy thủ tục của bạn.
- Bài 43 bạn cũng không có lập luận gì phản biện, chỉ tự xưng là lì. Tôi cũng lì lắm, tôi cũng tuổi trâu đây. Bạn cứ phản biện hết mình, có khi tôi sai thì sao? Có điều các phản biện từ đầu đến giờ chưa khiến tôi tự thấy sai. Các thành viên trên GPE đều biết tôi sẵn sàng nhận sai.

Nói cho rõ hơn ý của tôi để bạn phản biện đúng chỗ:
- Tôi nói rằng cần dùng 1 biến để tính số cần đưa vào <to> để khỏi tính lại nhiều lần. Dù cho tính nhanh hay chậm, nó cũng tính nhiều lần.
- Tôi đề ra nguyên tắc nên dùng biến trong tất cả các trường hợp (nhanh hay chậm), và khuyến cáo những người mới học nên làm theo.
- Tôi không nói gì đến vòng lặp ngoài hay trong, 1 vòng lặp hay 2 vòng lặp, tôi chỉ nói chung chung.
 
Upvote 0
theo lý luận của thầy (không phải em) thì thầy vui lòng cho biết lý do sao r lại lớn hơn ?
để em diễn giải vòng lặp theo kịch bản của thầy
khi r = 1 sau <to> là biểu thức cần tính => .[A1000000].End(xlUp).Row = 1 hợp lệ => thực hiện lệnh bên trong
.Range("A" & .[A1000000].End(xlUp).Row + 1).Value = r
mà .[A1000000].End(xlUp).Row + 1 lúc này bằng 2 => .[A2] = 1 hết 1 vòng nhảy step 1 => r = 2

khi r = 2 sau <to> là biểu thức cần tính vì .[A2] = 1 => .[A1000000].End(xlUp).Row phải = 2
vậy xin thầy cho biết lý do tại sao r = 2 và .[A1000000].End(xlUp).Row = 2 mà phải Break vòng lặp ?

Cái này hay nè, để tôi nghiên cứu thêm. Tôi chưa sai vì rõ ràng do phải tính toán nên thủ tục 2 của tôi chạy chậm hơn thủ tục 1 nhiều lần.
 
Upvote 0
khi nào thầy quay lại thì mời thầy ghé qua đây
http://stackoverflow.com/questions/...arp-execute-math-sqrt-more-slowly-than-vb-net
và để ý chỗ này trong đó
The C# implementation is recalculating Math.Sqrt(suspectPrime) each time through the loop, while VB only calculates it at the beginning of the loop. This is just due to the nature of the control structure. In C#, for is just a fancy while loop, while in VB it's a separate construct.

không biết ai sao chứ em rất có cảm tình với những người quyền cao chức lớn mà sẵn sàng thừa nhận sai lầm . bởi nó là tiền đề cho xã hội phát triển . tuổi em chỉ phát biểu được nhiêu đó thôi .
 
Upvote 0
Tôi thử code này :
Sub Test()
Dim i, j, arr()
ReDim arr(1 To 20)
For i = 1 To UBound(arr) Step 1
j = j + 1
ReDim arr(1 To 10)
Next
MsgBox j
MsgBox UBound(arr)
End Sub
Kết quả : j=20 ; UBound(arr)=10 . Vậy nó đâu có tính lại .
 
Upvote 0
Tôi không nghĩ vấn đề này lại cần phải tranh luận nhiều đến vậy. Vì mọi chuyện quá rõ ràng.
Như tôi đã nói. Dòng lệnh For... to... chỉ được thực thi 1 lần. Không thể đặt dòng lệnh này trong một vòng lặp khác rồi nói rằng nó không phải được thực thi 1 lần được. Vì mọi lệnh trong vòng lặp đều được lặp lại, đó là nguyên tắc cơ bản.

Ở bài 29, thủ tục Calc2 chậm hơn thủ tục Calc1 là do [XX2].End(xlToLeft).Column được tính lại theo số lần lặp của vòng lặp mẹ (vòng lặp For i...) chứ không phải được tính lại cho bản thân nó (vòng lặp For j...). Việc so sánh 2 thủ tục này với nhau là không công bằng. Nó giống như so sánh hai thủ tục sau:
PHP:
Sub Sub1()
EndR = [A1048576].End(xlUp).Row
For i = 1 To 1000000
    Debug.Print EndR
Next
End Sub
PHP:
Sub sub2()
For i = 1 To 1000000
    Debug.Print [A1048576].End(xlUp).Row
Next
End Sub

Nếu muốn so sánh, để so sánh công bằng thì phải so sánh như vầy:
Mã:
Sub Calc1()
Dim arr(1 To 100000, 1 To 100)
t = Timer
k = ([A150000].End(xlUp).Row - 1)': [COLOR=#ff0000]m = [XX2].End(xlToLeft).Column[/COLOR]
For i = 1 To k
    [COLOR=#0000cd][B]m = [XX2].End(xlToLeft).Column[/B][/COLOR]
    For j = 1 To m
        arr(i, j) = 0
    Next
Next
[A1] = Timer - t
End Sub
Mã:
Sub Calc2()
Dim arr(1 To 100000, 1 To 100)
t = Timer
For i = 1 To ([A150000].End(xlUp).Row - 1)
    For j = 1 To [XX2].End(xlToLeft).Column
        arr(i, j) = 0
    Next
Next
[B1] = Timer - t
End Sub
Ngoài ra, khi Run Step (F8) thì dòng lệnh nào được Highlight là dòng lệnh sắp thực thi. Nếu Run Step 1 vòng lặp For... to... sẽ thấy dòng For... to... chỉ Highlight 1 lần, sau dòng Next sẽ nhảy đến dòng dưới dòng For... to...
 
Upvote 0
khi nào thầy quay lại thì mời thầy ghé qua đâyhttp://stackoverflow.com/questions/...arp-execute-math-sqrt-more-slowly-than-vb-netvà để ý chỗ này trong đókhông biết ai sao chứ em rất có cảm tình với những người quyền cao chức lớn mà sẵn sàng thừa nhận sai lầm . bởi nó là tiền đề cho xã hội phát triển . tuổi em chỉ phát biểu được nhiêu đó thôi .
Đúng vậy, trong chừng mực cho phép thì bảo vệ quan điểm và giữ lập trường của mình là hợp lý, nhưng nếu quá bảo thủ, không thừa nhận sự thật thì không tốt lắm!
 
Upvote 0
khi nào thầy quay lại thì mời thầy ghé qua đây
http://stackoverflow.com/questions/...arp-execute-math-sqrt-more-slowly-than-vb-net
và để ý chỗ này trong đó
Hai hôm nay tôi quá bận không online lâu được nên bây giờ tôi mới viết trả lời.
Tôi đã nhận ra tôi sai 1 phần từ bài 45 của bạn mà không cần xem dẫn chứng. Tôi nói nhận sai 1 phần vì còn phân vân tại sao 2 thủ tục calc1 và calc2 của tôi ở bài 29, sửa lại ở bài 33 vẫn có sự khác biệt lớn. Lúc đó tôi còn thắc mắc:
Nếu chỉ tính 1 lần ở đầu vòng lặp, tại sao vòng lặp bên trong không tính 1 lần? Sau đó tôi không rảnh nên chưa tạo thêm các trường hợp để test.
Đến bài số 51 của huuthangbd, chỉ cần đọc 1 câu được tô đậm của anh ta, tôi thấy ngay vấn đề. Như vậy tôi đã sai khi tuyên bố luôn luôn tính lại. Xin cám ơn bạn doveandrose và bạn huuthang.

Nhân tiện, tôi cũng sai ở chỗ này: Tôi đã tính ra rằng calc2 tính lại 10 triệu lần, thực ra chỉ tính 100.000 lần, đó là số lần lặp của vòng for ngoài.

Dù sao, tôi cũng giữ nguyên ý kiến rằng, trong mọi trường hợp, người mới học nên đặt 1 biến để ghi lại giá trị <to>, dù 1 vòng lặp hay nhiều vòng lặp, để thống nhất cách viết code, sau này phải dùng 2 vòng lặp trở lên không bị chậm.

TB:
Tôi cũng lỳ vì tôi tuổi trâu, nên những phản biện cần phải có lập luận kèm theo, giải thích đúng và đúng chỗ tôi lập luận sai, tôi mới chịu. Chứ nếu chỉ đưa code chứng minh cái của mình mà không chỉ ra chỗ sai của code tôi viết thì tôi chưa chịu. Đó là tôi nói về bài 45 của bạn dove và bài 51 của huuthangbd, chỉ cần 1 câu đúng và đúng chỗ là tôi thấy ngay chỗ sai của mình. Kể cả bài 41 của bạn dove cũng chưa thuyết phục được tôi.

HTN đã viết:
Đúng vậy, trong chừng mực cho phép thì bảo vệ quan điểm và giữ lập trường của mình là hợp lý, nhưng nếu quá bảo thủ, không thừa nhận sự thật thì không tốt lắm!
Tôi không bảo thủ. Tôi chỉ tâm phục khẩu phục những lập luận chính xác chỉ ra được chỗ sai trong lập luận của tôi. Những bài viết của nghĩa không có giá trị lý luận, chỉ viết code đưa lên chứng minh chính mình. Trong bài tôi tính số lần lặp của calc4 và calc6, nếu là người lý luận tốt như huuthangbd, nghĩa chỉ cần nói 1 câu như huuthangbd thôi, tôi đã nhận sai. Bản than bài 34 Nghĩa đưa lên 2 thủ tục calc4 và calc6 cũng viết mơ hồ, lúc thì trong ngoài, lúc thì đầu cuối (không biết đầu cuối trong cùng thủ tục hay thủ tục đầu, thủ tục cuối). Lại còn nói tôi tưởng 100 ngàn. Lúc đó tôi tưởng 10 triệu 100 ngàn đấy chứ?
 
Upvote 0
Thấy có bạn so sánh cách hoạt động vủa vòng lặp theo C nên tôi góp thêm về nguyên tắc của vòng lặp FOR:

Mỗi ngôn ngữ có quy luật riêng về cách đếm sô lượt trong vòng lặp FOR:

- Ngôn ngữ cổ đại như FORTRAN 2: vòng lặp for luôn luôn chạy ít nhất 1 lần, không cần biết biến điều khiển có lớn hơn trị cuối hay không
- Ngôn ngữ Algol 60 (và Pascal cổ): biến điều khiển đếm được tính theo đầu vòng lặp, trong thân vòng lặp không thể thay đổi.
- Ngôn ngữ C (và các loại cùng họ): biến điều khiển và giới hạn vòng lặp hoàn toàn cơ động, muốn thay đổi ra sao cũng được. Trên thực tế, vòng lặp For trong C có thế có từ 0 đến n biến điều khiển. vd: for (;;) { code ở đây } và for (int i1 = 1, i2 = 10; i1 <= 10 && i2 >= 1; i1++, i2--) { code ở đây } đều làm được cả, code thứ nhất không có biến điều khiển và code thứ 2 có 2 biến điều khiển. Điều kiện giới hạn cuối cũng cơ động. Tức là cái biểu thức nằm giữa 2 dấu chấm phẩy của dòng for là một biểu thức trọn vẹn, luôn luôn được tính nghiêm chỉnh. (*)

Riêng VBA, biến điều khiển có thể thay đổi trong thân vòng lặp, và giới hạn cuốí chỉ tính 1 lần, ở đầu vòng lặp.

(*) chú thích: theo đúng lý thuyết thì vòng lặp C khôg thể đem so sánh với các ngôn ngữ khác, bởi vì C định nghĩa vòng lặp C theo nghĩa rất rộng
lệnh for được tiếp theo bởi mệnh đề điều khiển, nằm trong 2 dấu ngoặc, mệnh đề điều khiển gồm 3 phần, mỗi phần là 1 lệnh. Phân thứ nhất được xử lý trước khi bắt đầu vòng lặp, và chỉ xử lý 1 lần duy nhất. Phần thứ 2 được xử lý trước khi bước vào thân vòng lặp, và sẽ lặp lại sau phần 3. Phần thứ 3 được xử lý sau khi chạy xong dòng cuối cùng của vòng lặp. Như vậy, thoe lý thuyết, vòng lặp for hoàn toàn không cần có số đếm gì cả - tuy rằng viết code như vậy hơi kỳ quặc.

Trái hẳn với C, VBA xác định vòng lặp rất quy củ, lệnh for là một lệnh có biến đếm nghiêm chỉnh. Biến đếm được đặt một trị đầu và định một giới hạn cuối, hệ số tăng giảm cũng đươc định ngay trong dòng lệnh for. Cách thay đổi duy nhất là thay đổi biến ngay bên trong vòng lặp.
 
Upvote 0

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

Back
Top Bottom