Giới thiệu Cơ bản về vòng lặp For . . . next

Liên hệ QC

ptm0412

Bad Excel Member
Thành viên BQT
Administrator
Tham gia
4/11/07
Bài viết
13,784
Được thích
36,285
Donate (Momo)
Donate
Giới tính
Nam
Nghề nghiệp
Consultant
Nhân có người bạn hỏi về For . . . next, nay mình xin đóng góp những gì mình biết để các bạn chưa biết xem qua.
Trong các ngôn ngữ lập trình mình biết: VBA, VB6, FoxPro, Pascal đều có các cấu trúc vòng lặp. Vòng lặp là 1 cấu trúc chương trình cho phép 1 câu lệnh hoặc 1 nhóm câu lệnh thực hiện 1 số lần có giới hạn. Giới hạn này có thể biết trước và có thể không, nhưng phải có để máy tính ngừng lại khi đủ số lần lặp ấn định trước. Giới hạn này có thể xác định bằng 1 con số cụ thể, 1 con số là kết quả của 1 phép tính, và cũng có thể là 1 điều kiện thoát ra khỏi vòng lặp.
Vòng lặp for là đơn giản và dễ sử dụng hơn so với while do vì nó giới hạn cụ thể số vòng lặp.
Thí dụ: for i = 1 to 10, for i = 1 to len(chuoiA), for i = 0 to k*2 . . .
Như vậy, dòng lệnh nào đặt giữa For và Next sẽ thực hiện n lần, kết quả của dòng lệnh đó sẽ bị thay đổi n lần. Kết quả sau lần thực hiện thứ n mới được dùng cho các dòng lệnh sau cấu trúc For này hoặc là kết quả cuối cùng.
Ta có nhận xét rằng sau 1 vòng, biến i tăng lên 1 cho đến khi bằng số lần quy định.
Vậy vấn đề căn bản của chúng ta là gì?

1. Xác định rằng bài toán phải thực hiện nhiều lần 1 phép tính mới ra kết quả.
2. Xác định số lần tính đó.
3. xác định câu lệnh nào để thực hiện sự tính toán.

THí dụ đơn giản nhất: tính giai thừa của 6:
ta biết n! = 1 x 2 x 3 x.... x n.

1. vậy là thích hợp để dùng For.
2. xác định số lần tính: ta thấy 6! có 5 bài toán nhân. Ta chọn số vòng lặp là n. ta viết for i =1 to 5
3. xác định câu lệnh thực hiện nhân:
a. Phải đặt 1 biến là kq
b. giá trị của kq là giá trị của kết quả trước đó nhân với giá trị hiện tại của i vì i tăng lên sau mỗi vòng lặp, ta lấy luôn i làm thừa số cho phép nhân.
Vậy ta có câu lệnh: kq = kq * i
Đến đây ta phải giả định rằng khi chạy vòng đầu tiên, có trục trặc gì không. Có. Có ở chỗ chưa có giá trị ban đầu của kq nên không nhân đưộc. vậy ta gán giá trị ban đầu của kq là 1:
ta viết kq = 1 ở bên trên For
Thứ hai ta giả định rằng sau 5 vòng lặp giá trị của kq là như thế nào. ta được kq = 1 * 1 * 2 * 3 * 4 * 5
số 1 đỏ là giá trị ban đầu, số 1 đen đến số 5 là 5 giá trị của i, nhân 5 lần là do ta quy định.
Không phải là 6! mà chỉ là 5!. vậy ta sửa lại For i = 1 to 6

Cuối cùng ta có vòng lặp hoàn chỉnh:

kq = 1
For i = 1 to 6
kq = kq * i
next i

Để ứng dụng bài tập này lên Excel, ta cần đưa nó vào giữa cặp Private sub và end sub. Mở 1 Worksheet mới, tại cell A1 gõ vào 1 số bất kỳ để tính giai thừa. Ta muốn kết quả nằm ở cell B1. Ta cũng muốn xem sau 1 vòng tính, giá trị của kq là bao nhiêu nằm lần lượt ở A2, A3, . . .
Bạn đừng chê cái ý muốn này (tính giai thừa trò trẻ ấy mà có gì mà xem), có ích đấy khi bạn thử ở những vòng lặp phức tạp hơn, hãy đi từ dễ đến khó.
Tạo 1 nút lệnh đặt tên là cmb1, double click vào cmb1 vào cửa sổ code chèn vào giữa sub và end sub để có 1 macro hoàn chỉnh như sau:

Private Sub Cmb1_click()
num=range("sheet1!A1").value
Range("sheet1!A1:A100").clear
kq = 1
For i = 1 to num
kq = kq * i
range("sheet1!A1").Offset(i,0).value = kq
next i
range("sheet1!B1").value = kq
end sub


Sau đó trở lại Excel, click nút lệnh xem kết quả.

chú ý range("sheet1!A1").Ofset(i,0).value = kq đặt bên trong For next nên chạy 6 lần hiện lên 6 cell, vị trí quy định bởi Offset

Còn range("sheet1!B1").value = kq đặt ngoài vòng For next nên chỉ chạy 1 lần hiện lên ở 1 cell B1.

Lần sau mình sẽ giới thiệu những thí dụ khác khó dần lên, rồi 2 vòng For lồng nhau.
 
Lần chỉnh sửa cuối:
Mã:
Option Explicit
Option Compare Text
Sub zzz()
Dim a$, i%, j%
a = InputBox("XYZ hay ###?")
For i = 0 To 3
    For j = 1 To 3
        If a = "xyz" Then
            MsgBox "XYZ      nen thoat vong trong, ij = " & i & "-" & j
            Exit For
        Else
            MsgBox "###      nen van lan quan, ij = " & i & "-" & j
        End If
    Next j
            MsgBox "Dang o vong ngoai! va ij = " & i & "-" & j
Next i
            MsgBox "Cuoi cung: ij = " & i & "-" & j
End Sub

Ồ, em có nghịch thử thì giá trị i và j cuối cùng nếu trơn tru không bị thoát đều bị vượt cận trên. Lúc đầu em cứ nghĩ nó đạt đến cận trên là gán giá trị cố định luôn chứ. :wallbash: :wallbash: :wallbash:
1694773785195.png
 
Upvote 0
Mã:
Option Explicit
Option Compare Text
Sub zzz()
Dim a$, i%, j%
a = InputBox("XYZ hay ###?")
For i = 0 To 3
    For j = 1 To 3
        If a = "xyz" Then
            MsgBox "XYZ      nen thoat vong trong, ij = " & i & "-" & j
            Exit For
        Else
            MsgBox "###      nen van lan quan, ij = " & i & "-" & j
        End If
    Next j
            MsgBox "Dang o vong ngoai! va ij = " & i & "-" & j
Next i
            MsgBox "Cuoi cung: ij = " & i & "-" & j
End Sub

Ồ, em có nghịch thử thì giá trị i và j cuối cùng nếu trơn tru không bị thoát đều bị vượt cận trên. Lúc đầu em cứ nghĩ nó đạt đến cận trên là gán giá trị cố định luôn chứ. :wallbash: :wallbash: :wallbash:
View attachment 294879
Next là dòng lệnh chạy sau làm tăng giá trị biến lặp số nguyên lên 1 hoặc dịch vị trí bộ nhớ đối với mảng hoặc collection

Vậy nên khi kết thúc vòng lặp biến lặp số nguyên luôn lớn hơn giá trị đã gán

Để thoát luôn cả hai vòng lặp chỉ cần cho biến số i giá trị lớn hơn giá trị đã gán
I = 3 : Exit For
 
Upvote 0
Mã:
Option Explicit
Option Compare Text
Sub zzz()
Dim a$, i%, j%
a = InputBox("XYZ hay ###?")
For i = 0 To 3
    For j = 1 To 3
        If a = "xyz" Then
            MsgBox "XYZ      nen thoat vong trong, ij = " & i & "-" & j
            Exit For
        Else
            MsgBox "###      nen van lan quan, ij = " & i & "-" & j
        End If
    Next j
            MsgBox "Dang o vong ngoai! va ij = " & i & "-" & j
Next i
            MsgBox "Cuoi cung: ij = " & i & "-" & j
End Sub

Ồ, em có nghịch thử thì giá trị i và j cuối cùng nếu trơn tru không bị thoát đều bị vượt cận trên. Lúc đầu em cứ nghĩ nó đạt đến cận trên là gán giá trị cố định luôn chứ. :wallbash: :wallbash: :wallbash:
View attachment 294879
Khi j = 4 thì mới không thỏa điều kiện chạy từ 1 đến 3. Khi đó vòng lặp For mới dừng. Lợi dụng điều này, người lập trình mới đặt điều kiện If j > 3 hay là If j > Ubound(array) gì đó để giải quyết vấn đề của mình.
 
Upvote 0
. . . . . . . Cháu kiểm tra lại rồi, nó chỉ thoát vòng lặp bên trong thôi.
Đây là 1 cách để thoát 2 vòng lặp 1 khi thỏa điều kiện:
PHP:
Sub Thoat2VongLap()
 Dim J As Long, W As Integer, Tmp As Integer, Thoat As Boolean
 
 Randomize
 For J = 1 To 99
    For W = 1 To 35
        Tmp = W + J * Rnd() \ 1
        If Tmp Mod 13 = 0 Then
            Thoat = True:               Exit For
        End If
    Next W
    If Thoat Then
        MsgBox Tmp, , J & " <=> " & W:      Exit For
    End If
 Next J
End Sub

Bạn thử đưa ra 1 cách khác xem sao(!)
 
Upvote 0
Ồ, em có nghịch thử thì giá trị i và j cuối cùng nếu trơn tru không bị thoát đều bị vượt cận trên. Lúc đầu em cứ nghĩ nó đạt đến cận trên là gán giá trị cố định luôn chứ
For i = a To b
Next i

Gần như (sẽ giải thích tại sao "gần như") tương đương với (theo lô gic code):
i = a
VongLapFor_i:
If i > b Then GoTo ThoatVongFor_i
i = i + 1
GoTo VongLapFor_i
ThoatVongFor_i:

Gần như:
Hoạt động in hệt nhau.
Nhưng code thứ hai là code tự do cho vào đâu nó chạy đấy, thêm thắt gì nó chạy theo nấy.
Mặt khác, VBA đặt For-Next là một cơ cấu ngữ pháp có thêm vài tính chất bó buộc hơn:

1. là một cơ cấu trọn cho nên hai vòng For chỉ có thể lồng vào nhau chứ không thể móc vào nhau:
For i1 = 1 to 2
For i2 = 2 to 3
Next i2
Next i1 ' được, vòng i2 hoàn toàn nằm bên trong i1
...
For i1 = 1 to 2
For i2 = 2 to 3
Next i1
Next i2 ' không được, vòng i2 móc đuôi i1.
Lưu ý là nếu Next không đi với biến điều khiển thì nó được mặc định là thuộc về cái For gần nó nhất.
For i1 = 1 to 2
For i2 = 2 to 3
Next ' mặc định thành Next i2
Next ' mặc định thành Next i1

Code tự do thì muốn móc gì móc.

2. là một cơ cấu trọn cho nên lệnh Exit bên trong vòng lặp sẽ đưa nó rẽ nhánh đến lệnh ngay sau Next (lệnh đóng vòng lặp).

Trong khi đó, code tự do không thể dùng lệnh Exit mà phải dùng GoTo đưa nó đến cái Label cuối cùng để thoát.

3. For chỉ xét a và b một lần duy nhất, và luôn coi như đó là chận dưới chận trên vòng lặp. Bên trong vòng lặp, nếu ta gán cho a và b trị khác cũng không ảnh hưởng gì hết. i vẫn tỉnh bơ so sánh với trị b ban đầu. Muốn rút ngắn kéo dài thêm vòng lặp thì chỉ có thể thay đổi i. Đây là điều quan trọng cần phải hiểu rõ.

Code tự do không có việc xác định chận dưới chận trên này cho nên thay đổi trị b sẽ có khả năng rút ngắn kép dài số lần lặp.

Đây là 1 cách để thoát 2 vòng lặp 1 khi thỏa điều kiện:
...
Bạn thử đưa ra 1 cách khác xem sao(!)
Dùng lệnh GoTo:

For i1 = a To b
For i2 = c To d
IF ThiaDieuKien Then GoTo HetVong_i1
Next i2
Next i1
HetVong_i1:
 
Upvote 0
Lần chỉnh sửa cuối:
Upvote 0
Web KT
Back
Top Bottom