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,764
Được thích
36,260
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:
Nếu muốn thêm cả cột H nữa thì phải dùng 2 vòng For, bạn test thử xem có nhanh hơn chút nào không?
Mã:
Public Sub aviai()
Dim i As Long, Rng As Range, Lr As Long, d As Long, j As Long, d1 As Long
    Lr = Sheet1.Range("A10000").End(xlUp).Row
For i = 1 To Lr Step 7
        d = d + 1
        Sheet1.Range("A" & i,"B" & i).Resize(7, 2).Copy Sheet1.Range("F" & 1 + (d - 1) * 21).Resize(21, 2)
    For j = 1 To 3
        d1 = d1 + 1
        Sheet1.Range("H" & 1 + (d1 - 1) * 7) = "Tien " & j
    Next j
Next i
End Sub
 

File đính kèm

  • Giup Aviaiva.xlsm
    35.5 KB · Đọc: 23
Lần chỉnh sửa cuối:
Upvote 0
Trân trọng cảm ơn bác chuot0106; và bácBa Tê đã giúp đỡ.
bài bác batê chuẩn theo ý em, bài bác chuot0106 thì chưa đúng lắm, cột dữ liệu ở cột a không lặp mà nó chỉ có thế thôi.
Đại ý bài toán là
cột 1
Dữ liệu 1 ( có 1.1; 1.2; 1.3 ........)
Dữ liệu 2 (có 2.1; 2.2; 2.3 ........)
Dữ liệu 3 (có 3.1; 3.2; 3.2 .......)
cột 2
Dữ liệu 1 ( có 1.1; 1.2; 1.3 ........)
Dữ liệu 1 ( có 1.1; 1.2; 1.3 ........)
Dữ liệu 1 ( có 1.1; 1.2; 1.3 ........)
Dữ liệu 1 ( có 1.1; 1.2; 1.3 ........)
....... (lặp lại n lần)
Dữ liệu 2 (có 2.1; 2.2; 2.3 ........)
Dữ liệu 2 (có 2.1; 2.2; 2.3 ........)
Dữ liệu 2 (có 2.1; 2.2; 2.3 ........)
Dữ liệu 2 (có 2.1; 2.2; 2.3 ........)
....... (lặp lại n lần)
Dữ liệu 3 (có 3.1; 3.2; 3.2 .......)
Dữ liệu 3 (có 3.1; 3.2; 3.2 .......)
Dữ liệu 3 (có 3.1; 3.2; 3.2 .......)
Dữ liệu 3 (có 3.1; 3.2; 3.2 .......)
....... (lặp lại n lần)​
Yêu cầu là: chỉ nhập dữ liệu vào cột 1 sau đó copy toàn bộ dịnh dạng đã nhập sang cột 2 với số vòng lặp đã được cho trước
cho em hỏi thêm: ngoài for lồng nhau có cách nào không dùng for mà vẫn chuyển được dữ liệu cột 1 sang cột 2 mà tốc độ tính toán tăng lên đáng kể.
 
Upvote 0
Trân trọng cảm ơn bác chuot0106; và bácBa Tê đã giúp đỡ.
bài bác batê chuẩn theo ý em, bài bác chuot0106 thì chưa đúng lắm, cột dữ liệu ở cột a không lặp mà nó chỉ có thế thôi.
Thực ra dữ liệu lặp lại là do tôi copy xuống để Test thử khi dữ liệu lớn xem tốc độ có nhanh không thôi mà!
 
Upvote 0
Bạn đã test File ở #181 chưa mà bảo chưa chuẩn? tôi test thử thấy kết quả y chang kết quả của thầy Bate mà!
dạ, em test rồi, nó không copy dữ liệu sang, chỉ có như hình dưới sau khi em cho chạy

code của bác sau khi chạy



code của bác bate sau khi chay
 
Upvote 0
Nhờ các anh bổ sung vòng lập for cho đoạn code sau
Hiện tại mình chỉ lấy được 1 link
Mình muốn tại Cột C có bao nhiêu điều kiện thì lấy bấy nhiêu.
Mã:
Private Sub CommandButton1_Click()
Dim Arr, i As Long, k As Long, Count As Long
Dim Dic As Object
On Error Resume Next
Set Dic = CreateObject("Scripting.FileSystemObject")
    Arr = FilesFoldersList(Range("C5"), True, Range("C8") & "*.*", True)
        For i = LBound(Arr) To UBound(Arr)
        With Range("C8").Offset(i)
          .Offset(, 3).Hyperlinks.Add .Offset(, 3), Arr(i), , , "Click mo File"
        End With
        Next
End Sub
Còn đây là sub lấy link
Mã:
Function FilesFoldersList(ByVal RootFolder As String, ByVal ListType As Boolean, _
                          ByVal Search As String, ByVal InSub As Boolean)
  'ListType = True: Get Files list
  'ListType = False: Get Folders list
  Dim sComm As String, tmp As String, str As String, tmpFile, Arr
  On Error Resume Next
  If Right(RootFolder, 1) <> "\" Then RootFolder = RootFolder & "\"
  str = """" & RootFolder & IIf(ListType, Search, "") & """"
  
  With CreateObject("Scripting.FileSystemObject")
    tmpFile = .GetTempName
    sComm = "DIR " & str & " /ON /B /A" & IIf(ListType, "-", "") & "D-S" & IIf(InSub, "/S", " ") & " >" & tmpFile
    CreateObject("Wscript.Shell").Run "cmd /u /c " & sComm, 0, True
    With .OpenTextFile(tmpFile, 1, , -2)
      tmp = Trim(.ReadAll)
      If Right(tmp, 2) = vbCrLf Then tmp = Left(tmp, Len(tmp) - 2)
      If Len(tmp) Then
        If InSub = False Then tmp = RootFolder & Replace(tmp, vbCrLf, vbCrLf & RootFolder)
        FilesFoldersList = Split(tmp, vbCrLf)
      End If
      .Close
    End With
  End With
  Kill tmpFile
End Function
 
Upvote 0
Nhờ các anh bổ sung vòng lập for cho đoạn code sau
Hiện tại mình chỉ lấy được 1 link
Mình muốn tại Cột C có bao nhiêu điều kiện thì lấy bấy nhiêu.

Sửa công thức tại D8 thành vầy là được rồi:
Mã:
=HYPERLINK(C5&"\"&C8,"ClickMo")
 
Upvote 0
Em thấy topic này đang thảo luận về for next nên hỏi tiếp.
Nếu không đúng thì em se tạo topic mới.

Topic này mở ra chủ yếu để giới thiệu và hướng dẫn cho mọi người CƠ BẢN VỀ VÒNG LẬP. Để tránh làm loãng đề tài, mọi câu hỏi liên quan đến việc giải quyết nhu cầu cá nhân, các bạn nên mở topic khác hỏi nhé
Nếu bạn nào muốn "dợt" về cấu trúc vòng lập, cũng đã có hẳn một topic cho các bạn tại đây:
http://www.giaiphapexcel.com/forum/showthread.php?39326-Bài-tập-về-vòng-lặp
Rất mong các bạn hợp tác. Cám ơn!
 
Lần chỉnh sửa cuối:
Upvote 0
https://onedrive.live.com/?cid=AB17...B0BE!57001&parId=AB177E9F35D8B0BE!105&o=OneUp

Chào các bạn!
Mình mới tập tễnh vọc VBA nên còn gà mờ lắm, muốn viết 1 đoạn về vòng lặp mà mò mãi chưa ra. (như hình mình gửi trong link trên) mong
các bạn giúp đỡ.
CỘt A có dãy text kéo dài từ A5 - An
Cot B có dãy text kéo dài từ B8 - Bn
Cot C: cell C1 sẽ = cell đầu tiên <>"" (khác rỗng) của cột A (cell A5), ...... Cn=cell cuối cùng <>"" của cột A (cell n), Cn+1 = cell đầu tiên <>"" của cột B (cell B8) và Cn+n = cell cuối cùng <>"" của cột B (Cell Bn).
 
Lần chỉnh sửa cuối:
Upvote 0
Đây là 1 cách:

Mình mới tập tễnh vọc VBA nên còn gà mờ lắm, muốn viết 1 đoạn về vòng lặp mà mò mãi chưa ra. Mong giúp đỡ.
CỘt A có dãy text kéo dài từ A5 - An
Cot B có dãy text kéo dài từ B8 - Bn
Cot C: cell C1 sẽ = cell đầu tiên <>"" (khác rỗng) của cột A (cell A5), ...... Cn=cell cuối cùng <>"" của cột A (cell n), Cn+1 = cell đầu tiên <>"" của cột B (cell B8) và Cn+n = cell cuối cùng <>"" của cột B (Cell Bn).
PHP:
Option Explicit
Sub VongLap()
 Dim Rws As Long, J As Long
 Dim Rng As Range
 Columns("c:C").ClearContents
1
 Set Rng = Range([A1].End(xlDown), [A65500].End(xlUp))
 Rws = Rng.Rows.Count
 [c1].Value = Rng(1).Value
 For J = 2 To Rws
    [C65500].End(xlUp).Offset(1).Value = Rng(J).Value
 Next J
2
 Set Rng = Range([B1].End(xlDown), [B65500].End(xlUp))
 Rws = Rng.Rows.Count
 For J = 1 To Rws
    [C65500].End(xlUp).Offset(1).Value = Rng(J).Value
 Next J
End Sub
 
Upvote 0
PHP:
Option Explicit
Sub VongLap()
 Dim Rws As Long, J As Long
 Dim Rng As Range
 Columns("c:C").ClearContents
1
 Set Rng = Range([A1].End(xlDown), [A65500].End(xlUp))
 Rws = Rng.Rows.Count
 [c1].Value = Rng(1).Value
 For J = 2 To Rws
    [C65500].End(xlUp).Offset(1).Value = Rng(J).Value
 Next J
2
 Set Rng = Range([B1].End(xlDown), [B65500].End(xlUp))
 Rws = Rng.Rows.Count
 For J = 1 To Rws
    [C65500].End(xlUp).Offset(1).Value = Rng(J).Value
 Next J
End Sub


Thank bạn rất nhiều!
Chạy rất nuột.
Cho mình hỏi thêm tý: mình chưa hiểu lắm về ký hiệu 1, 2 và (1) - mình có tô đỏ trong trích dẫn. Bạn có thể giải thích để mình rõ hơn ko?
Xin cảm ơn trước!
 
Lần chỉnh sửa cuối:
Upvote 0
(1) Trong VBA người ta cho fép ghi thứ tự các dòng lệnh (Hiểu nôm na là đánh số các dòng lệnh)
Chuyện này có nhiều công dụng; 1 trong đó ta ta có thể xài f ương thức Goto,. . .
Nữa là: Khi cần VBA sẽ báo cho ta biết dòng lệnh nào trong macro đang gây lỗi. (Nhưng lúc đó ta cần fải đánh số các dòng lệnh 1 cách liên tục)
. . . . .
Những con số 1 & 2 bạn thấy ở đây ngõ hầu gúp ta fân tách nhóm các dòng lệnh cùng họ.

(2) Dòng lệnh
PHP:
[c1].Value = Rng(1).Value
Được diễn dịch là:
Lấy trị đang có ở ô đâu tiên của vùng ô trong biến Rng đem gán vô ô [C1]
Nếu ta có câu lệnh
Set Rng= Range("B3:D5")
thì Rng(1) sẽ là ô [B3]; Rng(2) sẽ là [C3],. . . .
Nói thêm: Nếu ta Set Rng= Range("B2:U2") ; thì Rng(1) vẫn fải là [B2] & Rng(2) vẫn là [C2]
Bạn có thể thử nghiệm với macro sau để hiểu rõ hơn

Mã:
Sub XYZ()
 Dim Rng As Range, Cls As Range 
 Dim J As Long 

 Set Rng= Range("B2:B13")
 For J = 1 To Rng.Cells.Count
    MsgBox Rng(j).value 
 Next j
 End Sub
 
Upvote 0
(1) Trong VBA người ta cho fép ghi thứ tự các dòng lệnh (Hiểu nôm na là đánh số các dòng lệnh)
Chuyện này có nhiều công dụng; 1 trong đó ta ta có thể xài f ương thức Goto,. . .
Nữa là: Khi cần VBA sẽ báo cho ta biết dòng lệnh nào trong macro đang gây lỗi. (Nhưng lúc đó ta cần fải đánh số các dòng lệnh 1 cách liên tục)
. . . . .
Những con số 1 & 2 bạn thấy ở đây ngõ hầu gúp ta fân tách nhóm các dòng lệnh cùng họ.

(2) Dòng lệnh
PHP:
[c1].Value = Rng(1).Value
Được diễn dịch là:
Lấy trị đang có ở ô đâu tiên của vùng ô trong biến Rng đem gán vô ô [C1]
Nếu ta có câu lệnh
Set Rng= Range("B3:D5")
thì Rng(1) sẽ là ô [B3]; Rng(2) sẽ là [C3],. . . .
Nói thêm: Nếu ta Set Rng= Range("B2:U2") ; thì Rng(1) vẫn fải là [B2] & Rng(2) vẫn là [C2]
Bạn có thể thử nghiệm với macro sau để hiểu rõ hơn

Mã:
Sub XYZ()
 Dim Rng As Range, Cls As Range 
 Dim J As Long 

 Set Rng= Range("B2:B13")
 For J = 1 To Rng.Cells.Count
    MsgBox Rng(j).value 
 Next j
 End Sub


Cảm ơn bạn rất nhiều!
Cho mình hỏi thêm tý:
Như trong file đính kèm thì cell C2 ([C65500].End(xlUp).Offset(1) giá trị phải bằng cell A4 (Rng(2)) là bằng rỗng chứ sao lại bằng cell A5 (giá trị = a1) được.
 

File đính kèm

  • Capture.jpg
    Capture.jpg
    45.1 KB · Đọc: 65
Lần chỉnh sửa cuối:
Upvote 0
Như trong file đính kèm thì cell C2 ([C65500].End(xlUp).Offset(1) giá trị phải bằng cell A4 (Rng(2)) là bằng rỗng chứ sao lại bằng cell A5 (giá trị = a1) được.

Vì bạn hỏi bài trong việc chạy vòng lặp nên nó thế!

Nó cũng đã chép ô rỗng [A4] đến [C2] ở lần chạy thứ 2 của vòng lặp 1;
Nhưng đến lần kế tiếp (của vòng lặp này) nó lại chép đè lên [C2] giá trị tại [A5]

Vì lúc đó [C65500].End(Xlup).Ofset(1) lại là [C2] chứ không fải [C3]

Còn nếu như bạn muốn nó fải rỗng như [A4] thì không xài vòng lặp được nữa; Lúc đó fải tiến hành fương thức khác, là chép cả cụm (cột).

Thân ái & vui vẻ nha!
 
Upvote 0
Vì bạn hỏi bài trong việc chạy vòng lặp nên nó thế!

Nó cũng đã chép ô rỗng [A4] đến [C2] ở lần chạy thứ 2 của vòng lặp 1;
Nhưng đến lần kế tiếp (của vòng lặp này) nó lại chép đè lên [C2] giá trị tại [A5]

Vì lúc đó [C65500].End(Xlup).Ofset(1) lại là [C2] chứ không fải [C3]

Còn nếu như bạn muốn nó fải rỗng như [A4] thì không xài vòng lặp được nữa; Lúc đó fải tiến hành fương thức khác, là chép cả cụm (cột).

Thân ái & vui vẻ nha!


Cảm ơn bạn rất nhiều!
Bạn có thể cho mình xin số đt ko? (hoặc FB, Skype gì cũng đc). Mình rất muốn học hỏi thêm nhiều thứ nữa từ bạn . :)
 
Lần chỉnh sửa cuối:
Upvote 0
chào mọi người,
Mình đang muốn viết lệnh trích ký tự trong VBA.
Ví dụ Range("A1") có giá trị H-AAAAxBBBBxCC/DDD, mình muốn trích các giá trị AAAA,BBBB,CC,DDD ra các ô khác nhau.
số ký tự AAA, BBBB, CC, DDD là biến thiên giữa các ký tự đặt biệt. Mọi người giúp mình với
 
Upvote 0
Web KT
Back
Top Bottom