Giới thiệu Cơ bản về vòng lặp For . . . next (2 người xem)

Liên hệ QC

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

ptm0412

Bad Excel Member
Thành viên BQT
Administrator
Tham gia
4/11/07
Bài viết
14,716
Được thích
37,418
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:
Giải thích một vài điều ngoài For . . . Next

Mấy hôm nay, các bạn cao thủ đã giúp cho một số bài tập hay, góp phần làm cho topic sôi động. Tuy nhiên ngoài ứng dụng For, các câu lệnh và các cấu trúc bên trong For của các bài giải đưa lên mới quá e rằng nhiều bạn không theo kịp.
Vậy tôi xin xen vào giải thích 1 vài cấu trúc lệnh mà mình biết (cũng có cái không biết luôn)/

1. Cấu trúc câu lệnh có điều kiện If . . . Then
a. Nói chung
là dạng có cấu trúc giống hàm if() của Excel:
Mở đầu là:
If <biểu thức luận lý> Then
Nếu BT luận lý đúng thì thi hành 1 số lệnh
lệnh 1
lệnh 2
.. .
Nếu BT luận lý sai:
Else
lệnh 3
lệnh 4
. . .
End If
Phần Else là tùy biến và có thể bỏ qua, cấu trúc If gọi là If khuyết.
b. Cấu trúc lồng nhau:

Nếu chọn lựa nhiều hơn 2, hoặc nhiều điều kiện hơn 1, ta dùng cấu trúc nhiều If lồng nhau. Nguyên tắc là bao nhiêu If . . . Then phải có bấy nhiêu End If, ngoài ra sử dụng cũng như các hàm if() lồng nhau của Excel.

c. Hàm IIf() của VBA:
VBA củng sử dụng 1 hàm tương tự y hệt của Excel, nhưng để phân biệt với If . . . Then, hàm này có tên gọi là IIf() với 2 chữ I. Cấu trúc:
IIf(<biểu thức luận lý> , giá trị nếu đúng , giá trị nếu sai)
Hàm này dùng trong trường hợp gán giá trị cho 1 biến với 1 điều kiện cho nhanh thay vì dùng If . . . Then.
Thí dụ:
- For iJ = 1 to IIf( a> b, b , a)
- kq = IIf (trich = " " , kq & trich , kq & "")


2. Cấu trúc chọn lựa nhiều điều kiện Select Case:
Khi có nhiều điều kiện, thay vì làm 4, 5 vòng If Then lồng nhau, người ta sử dụng Select Case
Cấu trúc:
Select Case <tên biến>
Case <các giá trị, hoặc các nhóm giá trị thứ nhất của biến>
Lệnh 1
Case < các giá trị, hoặc các nhóm giá trị thứ hai của biến>
Lệnh 2
. . .
Case Else
Lệnh khác
End Select

Trong đó mỗi Case là 1 gia trị, 1 nhóm giá trị, (liên tục hoặc không liên tục) của biến, mà ứng với các giá trị này của biến, VBA phải thực hiện cùng 1 lệnh (hoặc 1 loạt lệnh). Case khác, giá trị khác của biến, thực hiện lệnh khác. Các giá trị không đặc biệt hoặc đã loại trừ sau các Case trên, đưa vào thực hiện lệnh trong Case Else.
Các giá trị của biến nếu là số và liên tục có thể dùng cấu trúc to thí dụ Case 1 to 100
Các giá trị số nếu không liên tục và giá trị chuỗi, hoặc giá trị biến kiểu khác, thì liệt kê ra và dùng dấu phẩy phân cách chúng. Thí dụ:
- Case 1, 11, 21
- Case "now" , "tomorrow"
- Case 1 to 10 , 101 to 110

Trên đây là một vài cấu trúc thường gặp. Ngoài ra cò một số lệnh hoặc thủ tục lạ mà tôi cũng không biết, vậy các bạn nào đã sử dụng để giải bài tập trong topic này, xin vui lòng hướng dẫn cho tôi và các bạn mới về ý nghĩa và cách sử dụng.
Giá như các cao thủ khi post code lên có thể nói sơ qua về thuật toán (ý tưỡng tạo code dựa trên cơ sở nào)... Và giãi thích từng cụm lệnh dùng đễ làm cái gì thì... ngàn lần cảm ơn!

 
Upvote 0
Bác xem File đính kèm của em nhé (File số 3 ấy), sẽ thấy nếu là số âm nó sẽ bị sai. (thử với -999.999.999)
Bạn xem lại, số âm không sai, chỉ trừ khi số vượt ngoài phạm vi Single mới bị làm tròn 1 tí (-99.999.999 --> -100.000.000). Sửa khai báo biến lại double với sửa định dạng số trong kết quả là được mà.
Hì, hì, dấu đầu lòi đuôi, cái vụ già trẻ ấy mà.
Bạn xem giải thích một số lệnh trong bài của bạn, và cho một vài bài về bẫy lỗi đi, năn nỉ, năn nỉ.
 

File đính kèm

Upvote 0
Các bạn ơi... có thể nói thêm 1 tí về FOR nữa dc ko? Trong FOR này còn có cái gì có thể gọi là tuyệt chiêu (từ đầu topic đến giờ chưa nói đến)
Chẳng hạn có lần tôi thấy bạn Tigertiger làm như sau:
Mã:
For i = 1 to 10 Step -1
Step -1 là cái gì vậy? Tôi thì đoán chắc có lẽ là quét ngược từ 10 về 1 (đúng ko nhỉ?)
Ngoài ra các bạn có thể giới thiệu thêm về các vòng lập khác... dù sao nó cũng là vòng lập (thuật toán giống nhau)... chỉ khác về cú pháp, ví dụ là DO....LOOP gì gì đó
 
Upvote 0
ptm0412 đã viết:
Bạn xem giải thích một số lệnh trong bài của bạn, và cho một vài bài về bẫy lỗi đi, năn nỉ, năn nỉ.

Là chỗ nào vậy bác ?? Code của em đọc dễ hiểu mà.

Còn bẫy lỗi : Cái này phụ thuộc vào kinh nghiệm thôi. Khi mình nghĩ ra TH nào thì hàm trên sẽ bị lỗi thì mình cho nó vào bẫy lỗi. Viết 1 chương trình cũng thế mà.

VD : Khi bác tính hàm khai căn bậc chẵn, bác cũng biết rằng nếu nó âm thì không thể khai căn được.
Hoặc : Khi cộng số phần tử trong mảng, nếu số phần tử trong mảng ít hơn số phàn tử ta định cộng thì nó sẽ sai ngay (TH = thì bác SA đac có câu "CAN TIM SAO???")

Đấy là những kinh nghiệm khi ta làm về lĩnh vực đó (Kinh nghiệm công việc chứ không phải kinh nghiệm tin học)

Thân!
 
Upvote 0
Mã:
For [COLOR=red]i = 1[/COLOR] to [COLOR=red]10[/COLOR] Step -1
Nếu dùng vòng lập này thì phải như thế này
Mã:
For [COLOR=red]i = 10[/COLOR] to [COLOR=red]1[/COLOR] Step -1
 
Upvote 0
Mr Okebab đã viết:
Đấy là những kinh nghiệm khi ta làm về lĩnh vực đó (Kinh nghiệm công việc chứ không phải kinh nghiệm tin học)

Thân!
Cái mà mỉnh và càc bạn mới học cần là những kinh nghiệm của bạn đấy.
Đã đành kinh nghiệm tự mình trải qua mới nhớ lâu, nhưng bạn hãy chia sẻ mợt mớ như mình chia sẻ kiến thức về For, về Select case, về if. mặc dù đối với bạn là thường nhưng với người khác lại bổ ích. Nếu bạn có thể, xin cho biết các cấu trúc bạn thường sử dụng: on Error go to tùm lum, mỗi cái kèm theo 1 thí dụ nữa thì càng tốt. Như thí dụ tính căn bậc chẵn mà bạn nói, khi gặp số âm có bao nhiêu cách báo lỗi cho người dùng, hay chỉ đơn giản là exit sub với exit function. ngoài ra còn:
on error resume . . .
on error go to next
on error go to thissub(), thatsub()
. .. .
Đó là chưa kể cells() tiện dụng như thế nào hay sử dụng với mục đích thế nào so với range(); tại sao mình dùng offset mà bạn dùng thứ khác và cho rằng hay hơn; lệnh Set là gì; Câu trúc With là làm sao; tại sao người ta phải có Range(<này kia>).<này nọ> mà bạn chỉ dùng .<này nọ> . . . .

Còn nữa:
For Each Rng In CRng là cái gì? Có phải là kiểu đặc biệt của For không?
Dấu hai chấm (:) dùng trong trường hợp nào?
. . . .
Tóm lại có đủ thứ bạn biết mà nhiều người không biết. Bạn vui lòng giải thích thêm không? Chứ bạn giải toán lớp vỡ lòng, mà áp dụng Định lý Thalès, thì chúng tớ chịu thua.
Thân.
 
Lần chỉnh sửa cuối:
Upvote 0
Cái mà mỉnh và càc bạn mới học cần là những kinh nghiệm của bạn đấy. Như thí dụ tính căn bậc chẵn mà bạn nói, khi gặp số âm có bao nhiêu cách báo lỗi cho người dùng, hay chỉ đơn giản là exit sub với exit function. ngoài ra còn:
on error resume . . .
on error go to next
on error go to thissub(), thatsub(). .. .( Cái này chứng tỏ mình còn i tờ hơn bạn nhiều!)
Còn nữa:
For Each Rng In CRng là cái gì? Có phải là kiểu đặc biệt của For không?

.
Mã:
                                          [B] [SIZE="3"]Những ghi chép về        [/SIZE][/B]
                      [SIZE="4"]           [B] For Each . . . Next & Cách dùng trong excel[/B][/SIZE]

Ghi chép này liên quan đến vòng lặp For Each . . . Next
Syntax
For Each element In group
[statements]
[Exit For]
[statements]
Next [element]

Chúng ta sẽ xem xét đến vòng lặp For Each . . Next đơn giản sau đây
PHP:
Sub HideAllButOneSheet()
'Ẩn hết các Sheets khác tên ‘Sheet1 sau khi vòng lặp thực hiện’
 Dim wsSh As Worksheet
    For Each wsSh In Worksheets
        If wsSh.Name <> "Sheet1" Then wsSh.Visible = False
    Next wsSh
End Sub
Bây giờ chúng ta sẽ tìm hiểu kỹ hơn về vòng lặp dạng này trên trang tính. Macro (Mc) sau đây sẽ đưa ra thông báo về dữ liệu & địa chỉ của ô tại cột ‘A’
PHP:
Sub ForEachCollection()
Dim rRng As Range,  rCell As Range
    Set rRng = Range("A1", Range("A65536").End(xlUp))    
    For Each rCell In rRng
        MsgBox rCell.Value, , rCell.Value.Address
    Next rCell
End Sub
Để xem thứ tự mà excel truy xuất các ô, chúng ta xét đến bài tập sau: Chúng ta cần chú ý trình tự, xem thử Mc truy xuất hết cột này đến cột kia, hay ngược lại, hết hàng này đến hàng kia!
PHP:
Sub ForEach2Columns()
Dim rRng As Range,  rCell As Range
    Set rRng = Range("A1", Range("C65536").End(xlUp))    
    For Each rCell In rRng
        MsgBox rCell.Value, , rCell.Value.Address
    Next rCell
End Sub

Khi cần duyệt các phần tử của một mảng, chúng ta thực hiện như Mc (macro) sau
PHP:
 Option Base 1 ' Mới thêm '
Sub ForEachArray()
Dim lArray(10) As Long :				Dim lArr,  lCount As Long
    '"Gán trị bằng biến đếm cho mảng nhân với 10"  '
    For lCount = 0 To 10
        lArray( lCount) = lCount * 10
    Next lCount    
    lCount = 0
    'Khảo sát giá trị chứa trong mảng’
    For Each lArr In lArray
        MsgBox "The number " & lCount & " element in lArray is " & lArr
        lCount = lCount + 1
    Next lArr
End Sub
Bạn hãy tự thử sức: Với Mc thứ 2 đến thứ 4 bằng thêm câu lệnh thích hợp đễ thoát vòng lặp khi gặp điều kiện thỏa, ví dụ:
a./
Mã:
If rCells. Value > 50  then exit For
b./
Mã:
 If rCells > rCells.Offset(-1, 0) then Exit For
. . . .



Khi dùng vòng lặp trên trang tính chúng ta cần một số chú ý sau:
Cần cẩn trọng khi dùng vòng lặp:
Nhiều khi chúng ta phải dùng vòng lặp duyệt qua hết các ô của 1 vùng nào đó trên bảng tính; Với người thuộc loại I tờ như chúng ta, không phải lúc nào cũng chọn vòng lặp For . . Next hay For each. . Next là đúng đắn!
Nếu trên trang tính ta có vùng UsedRange là A2:E500; (Để biết thêm về UsedRange, ta tím trên diễn đàn nhờ đến sự trợ giúp của từ khóa UsedRange ). Nhiệm vụ đề ra là điền đầy vô những ô trống để có nội dung là ‘Blank’. Chúng ta xem xét hai macro (Mc) sau:
PHP:
Sub NoRight()
Dim Bcell As Range
2   For Each Bcell In Range("A2:E500")
	If IsEmpty(Bcell) Then Bcell = "Blank"
4   Next Bcell
End Sub
Câu lệnh 2 đến 4 là vòng lặp duyệt toàn bộ các ô trong vùng ‘A2:E500’;
Hàm IsEmpty() dùng để xác định đối tượng của hàm chứa nội dung rỗng hay không rỗng (nếu rổng hàm trả về True & ngược lại.)
Câu lệnh 3 có nội dung: Điền chữ ‘Blank’ khi gặp ô rỗng.
PHP:
Sub RightWay()
11    If WorksheetFunction.CountA(Range("A2:E500")) = 0 Then
12       MsgBox "All cells are empty", vbOKOnly, "For Each. . . Next"
13       Exit Sub
14    End If
15    On Error Resume Next
16    Range("A2:E500").SpecialCells(xlCellTypeBlanks) = "Blank"
17    On Error GoTo 0
End Sub
Cách thứ hai lại nhiều câu lệnh hơn; nhưng sẽ là đúng đắn hơn;
Các câu lệnh trước câu 15 chỉ là dùng hàm =COUNTA() trong excel để kiểm tra có ô rỗng trong vùng hay không;

Câu lệnh 15 chúng ta đã tình cờ gặp đâu đó rồi; Yêu cầu của nó là: Từ đây trở đi (cho đến khi gặp End Sub (hay Exit Sub. . . ) nếu bị lỗi (chương trình) thì bỏ qua (không) thực hiện dòng lệnh đó.
Trái tim của Mc là dòng lệnh 16; Nội dung là: Điền chữ ‘Blank’ cho những ô có đặc tính rỗng trong vùng ‘A2:E500’
Để hiểu thêm về SpecialCells, chúng ta cũng lại nhờ từ khóa SpecialCells (!)
Ta xét tiếp Mc thứ ba, mục đích của nó là tìm trên toàn bộ các ô của trang tính, ô nào chưa nội dung ‘Tìm Em’; Nếu máy có bộ nhớ kém thì chúng ta tiêu mất khoảng 5 phút cho Mc này chờ nó chạy xong; (Nếu không chờ được, chúng ta bấm các phím Ctrl+Break hay Esc
Để tìm đường khác gần hơn!)
PHP:
Sub WithLoop()
Dim rCell As Range
   For Each rCell In Cells
	If rCell.Value = " Tìm Em" Then
		rCell.Activate:			Exit For
  	End If
   Next rCell
End Sub
(Con đường khác đó sau này chúng ta sẽ tìm hiểu kỹ hơn, nêu ra đây là không tiện, (Đơn giản là biết dừng đúng lúc!. Chỉ xin gợi ý xíu, thế này:
PHP:
Sub NoLoop()
    If WorksheetFunction.CountIf(Cells, " Tìm Em ") = 0 Then
       MsgBox "You didn't type ' Tìm Em '", vbOKOnly, "GPE.com"
       Exit Sub
    End If    
	Cells.Find(What:="Find Me", , , , , , MatchCase:=False).Activate
End Sub
)


Chính sách chia để trị
Một khi chúng ta nhận lệnh tô màu cho các ô có số trị, kể cả các ô có công thức cho kết quả số trị. Chúng ta nên bắt đầu như Mc sau:
Mã:
[B]Sub FastestLoop()[/B]
Dim rCcells As Range, rFcells As Range
Dim rAcells As Range, rLoopCells As Range
[COLOR="Blue"]'Vùng đã sử dụng đem gán vô biến Acells (đã khai báo)[/COLOR]
  Set rAcells = ActiveSheet.UsedRange
rAcells.Select
On Error Resume Next                    [COLOR="blue"] 'Lựa ra những ô chứa công thức & số trị '
' Các ô chứ số trị chứa trong biến mới gán được gán vô biến Cccells '[/COLOR]
Set rCcells = rAcells.SpecialCells(xlCellTypeConstants, xlNumbers)
[COLOR="blue"]' Các ô chứa công thức (mà KQ trả về là số trị) chứa trong biến rAccells _
  đem gán vô biến rFcells '[/COLOR]
  Set rFcells = rAcells.SpecialCells(xlCellTypeFormulas, xlNumbers)
[COLOR="blue"]'Determine which type of numeric data (formulas, constants or none) '[/COLOR]

    If rCcells Is Nothing And rFcells Is Nothing Then
       MsgBox "You Worksheet contains no numbers":		       End
    ElseIf rCcells Is Nothing Then
       Set rAcells = rFcells       [COLOR="blue"] ' Công thức '[/COLOR]   
    ElseIf rFcells Is Nothing Then
       Set rAcells = rCcells        [COLOR="blue"]' Số trị '[/COLOR]
    Else
       Set rAcells = Application.Union(rFcells, rCcells)     [COLOR="blue"]'Cả hai '[/COLOR]
    End If
    On Error GoTo 0

   [COLOR="blue"] ' Tô màu cho những ô giá trị bé hơn 0 '[/COLOR]
    For Each rLoopCells In rAcells
        If rLoopCells.Value < 0 Then
            With rLoopCells
               .Interior.ColorIndex = 35	             
            End With
       End If
    Next rLoopCells
[B]End Sub[/B]
 
Lần chỉnh sửa cuối:
Upvote 0
Bài viết của bạn rất bổ ích, rất cám ơn bạn.
Nhân đây còn vài thắc mắc nhỏ:
1. Khai báo biến mảng, tớ thấy có người dùng:
- Dim aA(1 to 10) as Integer hoặc Dim aA(0 to 10) as Integer
- lại có người dùng Dim aA() sau đó khi đã gán nN = 10 thì ReDim aA(nN)
- Còn bạn thí dùng Dim aA(10)
Thắc mắc của tớ là Rốt cuộc trong 2 trường hợp 2 và 3, biến aA() có bao nhiêu giá trị?

2. Range("A1", Range("A65536").End(xlUp)) Range("A1:" & Range("A65536").End(xlUp)) có giống nhau không?

3. On Error GoTo 0 là đi đâu?
4. trong câu Dim lArray(10) As Long : Dim lArr, lCount As Long, dấu hai chấm có ý nghĩa gì?
5. Nhờ bạn giải thích cấu trúc:
If Then
. . . : End
ElseIf Then
. . .
ElseIf Then
. . .
End If

Cảm phiền bạn giải thích hộ, còn những UsedRange, SpecialCells() mình đi tìm trong help.
 
Upvote 0
Bạn hỏi làm mình giựt cả mình!

Sau khi đọc xong 5 câu của bạn, mình phải xem lại 1 lần nữa bài viết của mình, đễ kiểm tra chổ nào sai chăng (!?!)
Mặt khác mình cho rằng mình chỉ có 'nghĩa vụ' trả lời những gì bạn hỏi mà liên quan tới bài của mình thôi:
1. Khai báo biến mảng, tớ thấy có người dùng:
- Dim aA(1 to 10) as Integer hoặc Dim aA(0 to 10) as Integer
- lại có người dùng Dim aA() sau đó khi đã gán nN = 10 thì ReDim aA(nN)
- Còn bạn thí dùng Dim aA(10)
Thắc mắc của tớ là Rốt cuộc trong 2 trường hợp 2 và 3, biến aA() có bao nhiêu giá trị?
Mình phải xin lỗi bạn chỗ này! Để viết bài này, mình để toàn bộ các Mc trong 1 workbook, nhưng Mc có khai báo biến mảng đó không nằm ở trên cùng!

Trong phần Declarations của toàn bộ excel mình có ấn định dòng lệnh
Mã:
1 Option Explicit
& khi nào có dùng biến mảng thì mình luôn khai bào một tùy chọn thứ hai (đối với mình đây là nguyên tắc bắt buộc tự đề ra!)
Mã:
2  Option Base 1
Câu hỏi của bạn liên quan đến dòng lệnh 2 này
Theo mặc định (không có dòng 2) biến mảng khai báo sẽ bắt đầu từ số không
VD trường hợp không có dòng lệnh 2, khai
Redim Matric(10) hay Redim Matric(0 to 10) là có số phần tử như nhau
Tất nhiên ta cũng có thể khai
Redim Matric( 4 To 9) cả trong trường hợp này!
Ngược lại trong trường hợp tồn tại dòng lệnh 2 thì
Redim Matric2(10) chỉ có 10 phần tử mà thôi
Trong bài trên, chúng ta nói về Range & những gì xung quanh nó, nên theo mình tốt nhất tránh xa con số '0' ra í mà!
4. trong câu Dim lArray(10) As Long : Dim lArr, lCount As Long, dấu hai chấm có ý nghĩa gì?
Ngược với dấu '_' - dùng để nối các dòng lệnh dài trãi qua hơn 1 dòng lệnh; dấu ':' báo cho excel biết kể từ sau dấu này là dòng lệnh khác;
3. On Error GoTo 0 là đi đâu?
Hãy đi về vạch xuất phát!

Thân ái!
 
Lần chỉnh sửa cuối:
Upvote 0
Thú thật hồi trước giờ tôi viết code ào ào mà không biết bẫy và chả hiểu gì cả, chỉ đơn thuần là macro. Nay nhờ đọc bài của Bác Sa mới hiểu nguyên lý cấu trúc.
Cám ơn Bác Sa nhiều lắm, sẽ hậu tại 1 chầu Ken.
Gởi thêm 1 số cách về for i
PHP:
'==============================================================
' This workbook was prepared and coded by Martin Green to help
' Excel users learn about VBA. Visit my web site for tips and
' tutorials on Microsoft Office and details of my Training and
' Consultancy services: http://www.fontstuff.com
'==============================================================

Sub Loop1()
' This loop runs until there is nothing in the next column
    Do
    ActiveCell.FormulaR1C1 = "=Average(RC[-1],RC[-2])"
    ActiveCell.Offset(1, 0).Select
    Loop Until IsEmpty(ActiveCell.Offset(0, 1))
End Sub

Sub Loop2()
' This loop runs as long as there is something in the next column
    Do While IsEmpty(ActiveCell.Offset(0, 1)) = False
    ActiveCell.FormulaR1C1 = "=Average(RC[-1],RC[-2])"
    ActiveCell.Offset(1, 0).Select
    Loop
End Sub

Sub Loop3()
' This loop runs as long as there is something in the next column
    Do While Not IsEmpty(ActiveCell.Offset(0, 1))
    ActiveCell.FormulaR1C1 = "=Average(RC[-1],RC[-2])"
    ActiveCell.Offset(1, 0).Select
    Loop
End Sub

Sub Loop4()
' This loop runs as long as there is something in the next column
' It does not calculate an average if there is already something in the cell
    Do
    If IsEmpty(ActiveCell) Then
        ActiveCell.FormulaR1C1 = "=Average(RC[-1],RC[-2])"
    End If
    ActiveCell.Offset(1, 0).Select
    Loop Until IsEmpty(ActiveCell.Offset(0, 1))
End Sub

Sub Loop5()
' This loop runs as long as there is something in the next column
' It does not try to calculate an average if there is already something in the cell
' nor if there is no data to average (to avoid #DIV/0 errors).
    Do
    If IsEmpty(ActiveCell) Then
        If IsEmpty(ActiveCell.Offset(0, -1)) And IsEmpty(ActiveCell.Offset(0, -2)) Then
            ActiveCell.Value = ""
        Else
            ActiveCell.FormulaR1C1 = "=Average(RC[-1],RC[-2])"
        End If
    End If
    ActiveCell.Offset(1, 0).Select
    Loop Until IsEmpty(ActiveCell.Offset(0, 1))
End Sub

Sub Loop6()
' This loop repeats for a fixed number of times determined by the number of rows in the range
    Dim i As Integer
    For i = 1 To Selection.CurrentRegion.Rows.Count - 1
    ActiveCell.FormulaR1C1 = "=Average(RC[-1],RC[-2])"
    ActiveCell.Offset(1, 0).Select
    Next i
End Sub

Sub Loop7()
' This loop repeats a fixed number of times getting its reference from elsewhere
    Dim i As Integer
    Dim intRowCount As Integer
    intRowCount = Range("A1").CurrentRegion.Rows.Count - 1
    For i = 1 To intRowCount
    ActiveCell.FormulaR1C1 = "=Average(RC[-5],RC[-6])"
    ActiveCell.Offset(1, 0).Select
    Next i
End Sub

Sub Loop8()
' This loop does the calculating itself and writes the result into each cell
    Do
    ActiveCell.Value = WorksheetFunction.Average(ActiveCell.Offset(0, -1).Value, ActiveCell.Offset(0, -2).Value)
    ActiveCell.Offset(1, 0).Select
    Loop Until IsEmpty(ActiveCell.Offset(0, 1))
End Sub
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
For . . Next mức độ 3: nhiều vòng For lồng nhau.

Trong các bài post của một số bạn , ngoài các câu lệnh khó mà mình đã hỏi mong được giải đáp, cho mọi người và cho cả mình nữa; các bạn đã dùng đến các vòng For lồng nhau.
Các câu hỏi đã được giải đáp, mong các bạn mới học hãy lưu tâm, vì rất bổ ích.
Còn cấu trúc For lồng nhau sau đây tôi xin giới thiệu:

1. Mục đích:
Xin nhắc lại mục đích của vòng lặp For đơn: Vòng lặp For nhằm giúp cho người dùng thực hiện lệnh hoặc những lệnh giống nhau nhiều lần mà không cần phải gõ bằng ấy lần câu lệnh. Vậy khi thực hiện 1 dự án hay đơn giản là viết 1 đoạn code mà bạn thấy rằng có 1 vài câu lệnh sẽ phải thực hiện 1 số lần biết trước, thì hãy dùng For. Tất nhiên là đúng theo bạn Sa_DQ: không phải lúc nào dùng For cũng là tốt nhất, nhưng ý nghĩa của For đúng là như vậy.
Nhắc thêm về số lần lặp của For: Số lần này cần phải biết trước khi gán For i = ... to ... Số lần lặp này biết trước, không nhất thiết phải là con số cụ thể, mà cũng có thể là kết quả của 1 phép tính thông qua 1 con số, 1 biến hay vài biến. Phép tính nói trên cũng không nhất thiết là cộng trừ nhân chia, lũy thừa căn số; mà cũng có thể là 1 hàm. Số lần lặp này cũng có thể tùy chọn linh hoạt theo 1 điều kiện nào đó.
Nói sang vòng lặp lồng nhau. Khi bạn thấy 1 số lệnh cần thực hiện n lần cho ra 1 kết quả, bạn dùng For. Khi bạn thấy cũng bài toán như vậy nhưng cần nhiều kết quả tương tự chứ không phải 1, bạn dùng 2 vòng For lồng nhau.
Suy luận theo hướng này, bạn sẽ thấy cần dùng 3 , 4 vòng lặp For lồng nhau dùng cho những bài toán phức tạp hơn.

2. Thí dụ:

- Để đếm số ký tự "a" hoặc "A" trong 1 chuỗi Mystr, bạn dùng For với phần code chính như sau:

For i = 1 To len(Mystr)
Tam = LCase(Mid(Mystr, i, 1))
If Tam = "a" Then
ltcount = ltcount + 1
End If
Next i

- Nhưng bạn lại muốn đếm tất cả các ký tự từ A đến Z trong chuỗi trên, bạn không thể viết 26 lần doạn code trên cho 26 ký tự. Vậy bạn dùng 1 vòng lặp For mới, chạy 26 vòng, mỗi vòng là 1 lần chạy đoạn code trên. Hay nói rõ hơn là 2 vòng For lồng nhau.

- Rồi bạn lại muốn đếm tương tự như vậy cho 5 chuỗi khác nhau, và bạn dùng vòng lặp For thứ 3 chạy 5 lần vòng For thứ nhì (trong đó có 26 lần chạy vòng For thứ nhất).
Tổng cộng nhóm các dòng lệnh trong đó có lệnh Tam = LCase(Mid(Mystr, i, 1)) chạy 26 x 5 x len(MYstr) lần.

3. Giải:
Sau đây là đoạn code gợy ý cho 2 vòng của bài tập sau:
Cho 1 chuỗi ở cell A1, đếm lần lượt các ký tự từ a đến z có trong chuỗi, chữ thường và chũ hoa đếm chung. Cho trước dãy B1:B26 là các ký tự từ a đến z. Kết quả cho hiện lên ở cột C bắt đầu từ C1.

Mã:
Sub Dem()
Dim Length, Ltcount, i, j, k As Integer
Dim Mystr, Tam, Ch(1 To 26) As String
Dim KqCel As Range
[COLOR=green]' Phần này gán giá trị cho biến Ch()[/COLOR]
For k = 0 To 25
Ch(k + 1) = Range("B1").Offset(k, 0).Value
Next k
[COLOR=green]' Phần này gán giá trị cho các biến khác[/COLOR]
Mystr = Range("A1").Value
Length = Len(Mystr)
Ltcount = 0
Set KqCel = Range("C1")
[COLOR=green]' Phần code chính[/COLOR]
For j = 1 To 26
      For i = 1 To Length
          Tam = LCase(Mid(Mystr, i, 1))
          If (Tam) = Ch(j) Then
          Ltcount = Ltcount + 1
     End If
      Next i
     KqCel.Offset(j - 1, 0).Value = "So ky tu" & "'" & Ch(j) & "' la " & Str(Ltcount)
     Ltcount = 0
Next j
End Sub

Khi dùng thử bài tập này các bạn lưu ý chuỗi ở cell A1 nên dùng tiếng Anh hoặc tiếng Việt không dấu. Nếu dùng tiếng Việt có dấu nên dùng Font Unicode, khi đó bạn có thể đếm chữ cái ă, â, ô, ố, ê, ế . . .
Không dùng Font VNi-.. vì mỗi chữ cái nguyên âm có dấu của Font loại này là 2 ký tự. kết quả hiện lên bạn khó kiểm tra đúng sai.

4. Bài tập 1 mức độ 3:
Kết quả của đọan code trên cho số đếm dược của mọi ký tự cho trước trong cột B, không có cũng cho kết quả là 0.
bạn hãy sửa lại để không hiện các kết quả zero.
 
Lần chỉnh sửa cuối:
Upvote 0
Bài tập 2 mức độ 3 (mở giành cho mọi trình độ!)

Trò chơi ô chữ:
Tóm lược:
Trong Sheet1 có các từ ngữ mà chủ đề của chúng về thể thao
Các từ được xếp vào các cột theo cùng độ dài (chữ tiếng việt không dấu)
Nhiệm vụ:
Tìm các từ có nghĩa mà chúng thỏa điều kiện: tại bốn điểm giao nhau (xem Sheet2) có cùng chữ cái (giữa 2 hay 3, . . từ không có khoảng trống)

Xem thêm tại file đính kèm
 

File đính kèm

Upvote 0
Mức độ 4: Vòng lặp For . . . Next trong hàm đệ quy

Đây không hẳn là 1 mức độ khó hơn của For, chỉ là 1 trường hợp dùng For trong lý thuyết về hàm đệ quy.
Vậy đệ quy là gì?
Các đoạb code khi chuyển sang Function thì gọi là hàm. Nếu trong hàm có dòng lệnh tự gọi chính hàm này ra thực thi lần 2, lần 3, . . . thì gọi là đệ quy.
Trường hợp dùng đệ quy:
Trong quá trình tính toán, sau một vài lệnh ta có 1 kết quả hoặc kết quả tạm đang lưu giữ trong 1 biến nào đó, thí dụ biến Tam.
Ta lại thấy rằng để đi đến kết quả cuối cùng, ta phải dùng lại các câu lệnh trên 1 lần nữa nhưng không phải tính toán trên các tham số ban đầu mà là tính toán trên cái biến Tam này. Vậy ta dùng 1 câu lệnh gọi chính hàm này ra chạy, nhưng tham số lần này của hàm là biến Tam.

Lý thuyết là như vậy nhưng thực sự trong công việc hàng ngày của phần lớn nhân viên công sở, kể cả nhân viên kỹ thuật, cũng ít dùng.
Ở đây ta chỉ cần biết định nghĩa của nó thôi để áp dụng cho trường hợp sau:

Trong bài tập 2 mức độ 1, chắc các bạn còn nhớ ta đã đọc tách số từ 1 chuỗi copy từ word sang như "1.254.338 VND" hoặc "USD 25,250,110". Ở mức độ 1, ta mới chỉ tách được nếu số trong chuỗi là số nguyên dương. Nay ta muốn mở rộng đọc cả số âm và số thập phân với dấu phân cách thập phân khác nhau (chấm hoặc phẩy).

Muốn vậy thoạt tiên ta nghĩ rằng khó, nhưng nếu ta tách chuỗi ra làm 2 phần, đọc riêng phần nguyên và phần thập phân theo cách của bài tập mức độ 1thì sao? Sau đó dùng 1 vài phép tính đổi phần thập phân (đang là số nguyên 2 theo cách đọc trên) thành số dạng 0,xxx rồi cộng phần nguyên 1 và phần 0,xxx này.
Nhu vậy, vô tình bạn đã nghĩ đến đệ quy:
Lần thứ nhất, dùng hàm Docso() đọc đến khi gặp ký tự là dấu thập phân (chấm hoặc phẩy) thì ngừng để được phần nguyên 1. (gán vào biến tạm 1)
Sau đó gọi hàm Docso() lần 2 đọc phần còn lại của chuỗi để có phần thập phân ở dạng số nguyên 2 (gán vào biến tạm 2)
Biến tạm 2 nếu chia cho 1 số 10^n thích hợp sẽ có phần thập phân dạng 0,xxx.
Cuối cùng cộng phần nguyên và phần thập phân, ta có kết quả.

Còn nếu số âm ư? trong quá trình đọc tứng ký tự của chuỗi, nếu gặp dấu trừ ("-") thì để dành đấy, đến cuối lấy kết quả nhân với -1. Dễ quá phải không?

Còn về dấu thập phân "," hoặc "." thì xử lý sao? Cái này ta buộc người sử dụng làm, vì chỉ người sử dụng hàm mới biết chuỗi của họ copy từ đâu, dấu thập phân là dấu gì. Khi họ xác định dấu thập phân là dấu gì, ta mới dùng ký tự đó làm dấu hiệu phân cách giữa phần nguyên và phần thập phân.
Muốn buộc người sử dụng làm thì cho thêm vào hàm của ta 1 tham số DauTP cho họ cung cấp.
Nếu muốn tham số này là tùy biến có thể bỏ qua khi đọc số nguyên trong chuỗi, ta khai báo tham số là Optional.
Xem phần code sau của hàm:
Mã:
Function Docso(Mystr As String, Optional Dautp As String) As Double
Dim Kqng, Kqtp, Kqtam, Neg As Integer
Dim Sotp As Double, Le As Byte
Neg = 1
Le = 0
For i = 1 To Len(Mystr)
    Tam = Mid(Mystr, i, 1)
    Select Case Tam
        Case 0 To 9
            Kqtam = Kqtam * 10 + Tam
        Case "-"
            Neg = -1
        Case Dautp
            Kqng = Kqtam
            Le = 1
            [COLOR=navy]Mystr = Right(Mystr, Len(Mystr) - i)[/COLOR]
            [COLOR=red]Kqtp = Docso(Mystr)[/COLOR]
            Sotp = Kqtp * 10 ^ (-Len(Kqtp))
        End Select
Next i
Select Case Le
Case 0
Docso = Kqtam
Case 1
Docso = (Kqng + Sotp)
End Select
Docso = Docso * Neg
End Function

Mời các bạn tham khảo.
Trong đó:
- câu Mystr = Right(Mystr, Len(Mystr) - i) là xác định phần còn lại của chuỗi, dùng để đọc số thập phân.
- câu Kqtp = Docso(Mystr) là gọi chính hàm Docso() ra chạy lần 2, tham số DauTP bỏ qua khồng cần dùng vì đã là phần thập phân không thể còn dấu thập phân nào đứng sau nó nữa.
- Hàm này chưa có phần báo lỗi.
 
Lần chỉnh sửa cuối:
Upvote 0
Một cách kiểm tra lỗi của code mới tạo

Khi bạn mới viết được 1 đoạn code, bạn cần phải chạy thử nó nhiều lần với các tham số khác nhau, những trường hợp khác nhau mục đích là xem đoạn code mới tạo này chạy có đúng trong mọi trường hợp, mọi hoàn cảnh hay không.
Khi một đoạn code bị lỗi, bạn lại cần biết nó lỗi ở dòng nào.
Nếu lỗi khiến cho code bị dừng lại thì dễ, bạn nhấn nút Debug sẽ thấy trong cửa sổ code, dòng lệnh lỗi bị tô màu vàng. Nhưng cũng có khi dòng bị tô màu lại là dòng đầu tiên khai báo sub hoặc khai báo Function, bạn sẽ bị lúng túng vì không biết phải sửa ở đâu.
Cũng có khi code chạy bình thường không bị ngừng nhưng kết quả xuất ra lại không như bạn mong đợi. Có nhiều nguyên nhân:
- Thuật toán chưa đúng
- Câu lệnh chưa chính xác
- Các câu lệnh bị đảo thứ tự hoặc nàm sai chỗ (trong hay ngoài vòng lặp)
- Select case bỏ sót 1 case
- Điều kiện if không đặt đk đúng

Vậy bạn hãy áp dụng phương pháp này khi chạy kiểm tra code: Đánh dấu một hoặc 1 số dòng lệnh trên thanh dọc bên lề trái. Chọn các dòng bạn quan tâm, hoặc dòng bạn nghĩ là cần kiểm tra, hoặc đánh dấu hết các dòng. Khi đó dòng lệnh đánh dấu sẽ được tô màu đỏ sậm và 1 hình tròn màu đỏ xuất hiện trên thanh dọc, ngang với dòng đánh dấu.
Tiếp theo bạn tiến hành chạy code. Khi code chạy đến dòng lệnh nào bạn đánh dấu, code sẽ bị Pause lại và dòng lệnh đó chuyển màu vàng. Nhớ rằng code bị Pause ngay trước khi thực hiện câu lệnh bị đánh dấu. Muốn cho lệnh chạy tiếp, bạn nhấn nút hình giống nút Play trên tool bar.
Phần quan trọng nhất: Khi code đang trong tình trạng Pause, bạn rà con trỏ chuột theo từng câu lệnh, khi con trỏ chỉ tới từng tên biến, từng giá trị của cell trong câu lệnh, VBA sẽ cho biết giá trị của biến hay của cell tại thời điểm đó. Bạn so sánh giá trị đó của biến với giá trị mà bạn nghĩ đáng lẽ nó phải có. Nếu giống nhau thì chạy tiếp, kiểm tra tại dòng lệnh đánh dấu tiếp theo.
Thí dụ như vòng lặp For (đang trong topic For mà). Bạn nghĩ rằng khi For chạy 4 vòng (i = 4) thì biến tạm nào đó phải có giá trị = 2, khi For chạy 5 vòng ( i có giá trị 5) biến tam phải =3. nhưng khi Rà chuột, bạn thấy khi i = 4 vẫn còn đúng, nhưng khi i = 5 nhưng tam = 2, có nghĩa là câu lệnh hoặc vài câu lệnh phía trước câu đánh dấu có vấn đề. Bạn sẽ tập trung suy nghĩ, đánh giá lại đoạn lệnh trước đó.
Nếu vẫn không nghĩ ra, bạn đánh dấu nguyên 1 đoạn lệnh từng dòng một và kiểm tra theo từng bước như vậy.
Biện pháp này khá hữu dụng cho cả người mới học lẫn người đã rành.
 
Upvote 0
Để kết thúc: Các loại vòng For đặc biệt

Các loại vòng For đặc biệt:

1. Vòng For bị giảm thiểu số lần lặp:
Khi gặp điều kiện nào đó như đã tìm được đáp số, dùng câu lệnh Exit For để thoát ra khỏi vòng lặp mà không chờ chạy đủ số vòng ấn định trước. Xem bài # 59

2. Vòng For Each . . . In . . . Next:
Xem bài # 126 của Sa_DQ

3. Vòng For có bước khác 1:
là vòng For có thêm tham số step. Cấu trúc: For i=1 to n step m
Thông thường For i = 1 to n có step 1, nếu bạn muốn tính với chỉ số chẵn hoặc số lẻ, hoặc trên bảng tính bạn chỉ muốn xử lý dòng lẻ bạn dùng step 2.
Còn nếu bạn muốn giảm thiểu vòng lặp và vì bạn nghĩ chạy từ cuối lên đầu mau chóng gặp kết quả hơn bạn dùng step âm: For i = n to 1 step -1, sau đó khi gặp kq thì Exit For.

Để kết thúc

Đến đây tôi xin tạm kết thúc loạt bài về For . . Next. Mong rằng ít nhiều giúp được cho các bạn mới học.

Các bạn cứ xem kỹ các bài giới thiệu, các bài tập và bài giải, các bài hướng dẫn thêm của các cao thủ, sau đó bạn cứ lùng sục trên diễn đàn, gặp For là xem, cốt để hiểu cấu trúc, lệnh chưa biết thì tìm hiểu thêm sau, chắc hẳn các bạn sẽ tiến bộ. Nếu còn gì thắc mắc, đừng ngại hỏi. Nếu tôi không giải thích được thì còn nhiều người khác.

Hẹn gặp lại,
 
Upvote 0
1: Cho 1 chuỗi tại cell A1, đảo ngược chuỗi từng ký tự một cho ra 1 chuỗi mới ở cell B1.

Do mới tập thử làm mà code không có chạy, nhờ các Anh Chị chỉ giúp chỗ sai và giải thích giúp. Thanks
Mã:
Sub DaoChuoi()
mystr = Range("sheet4!A1").Value
Range("sheet4!A2:d100").Clear
For iZ = Len(mystr) - 1 To 1
kq = Mid(mystr, iZ + 1, 1) & Mid(mystr, iZ, 1)
Range("sheet4!A1").Offset(iZ, 0).Value = kq
Next iZ
Range("sheet4!B1").Value = kq
End Sub
 
Upvote 0
Do mới tập thử làm mà code không có chạy, nhờ các Anh Chị chỉ giúp chỗ sai và giải thích giúp. Thanks
- Nếu bạn For -Next từ 1 số lớn giảm dần xuống 1 số nhỏ phải thêm Step -1
- Không có lý do gì phải bỏ bớt 1 ký tự Len(mystr) - 1
- Nối từng ký tự vào kq, chứ không phải nôi từng ký tự vào ký tự đứng kế nó: kq = kq & Mid(mystr, iZ, 1)

Code cuối cùng là:

PHP:
Sub DaoChuoi()
mystr = Range("sheet4!A1").Value
Range("sheet4!A2:d100").Clear
For iZ = Len(mystr) To 1 Step -1
    kq = kq & Mid(mystr, iZ, 1)
    Range("sheet4!A1").Offset(iZ, 0).Value = kq
Next iZ
Range("sheet4!B1").Value = kq
End Sub
 
Upvote 0
Do mới tập thử làm mà code không có chạy, nhờ các Anh Chị chỉ giúp chỗ sai và giải thích giúp. Thanks
Mã:
Sub DaoChuoi()
mystr = Range("sheet4!A1").Value
Range("sheet4!A2:d100").Clear
[B]For iZ = Len(mystr) - 1 To 1
[/B]kq = Mid(mystr, iZ + 1, 1) & Mid(mystr, iZ, 1)
Range("sheet4!A1").Offset(iZ, 0).Value = kq
Next iZ
Range("sheet4!B1").Value = kq
End Sub

Không biết Range("sheet4!A1") của bạn chứa gì nhưng chắc là do là Len(mystr) - 1 >1 đó bạn.
Bạn hãy thí nghiệm với đoạn code sau, thử thay các giá trị màu đỏ xem:
Mã:
Sub Test()
[B]For k = [COLOR=#ff0000]5[/COLOR] To [COLOR=#ff0000]2[/COLOR]
[/B]MsgBox k
Next
End Sub
 
Upvote 0
- Nếu bạn For -Next từ 1 số lớn giảm dần xuống 1 số nhỏ phải thêm Step -1
- Không có lý do gì phải bỏ bớt 1 ký tự Len(mystr) - 1
- Nối từng ký tự vào kq, chứ không phải nôi từng ký tự vào ký tự đứng kế nó: kq = kq & Mid(mystr, iZ, 1)

Code đã sửa chạy tốt, cám ơn Anh với những giải thích rất cặn kẽ, đã hiểu thuật toán để sửa code và học thêm được Step-1.
 
Upvote 0
Mình thì lại thích chạy tới, khi nào hết cách mới lùi, hì:
Mã:
Sub Test()
    mystr = Range("sheet4!A1").Value
    Range("sheet4!B1").ClearContents
    For k = 1 To Len(mystr)
        kq = Range("sheet4!B1").Value
        Range("sheet4!B1").Value = Mid(mystr, k, 1) & kq
    Next
End Sub
 
Upvote 0
Mình thì lại thích chạy tới, khi nào hết cách mới lùi, hì:
Sao không phải là:

PHP:
 kq =  Mid(mystr, k, 1) & kq

Mà chạy vòng vòng mắc công zậy? Đằng nào gán xuống B1 liên tục vậy cũng có kịp ngó thấy đâu, lại còn gây chậm chạp ra nữa.
 
Upvote 0
Rất cám ơn ptm0412, những bài tập cơ bản như zậy rất thích hợp cho những người ko rành excel như mình.
Nếu được mong bạn sẽ có thật nhiều bài hữu ích tương tự như zậy nữa.
Mình sẽ theo dõi bài tiếp theo của bạn.
Thanks
 
Upvote 0
Một chủ đề rất bổ ích

Cái này rất bổ ích cho những người mới tập VBA như bọn em.

Thật không thể tin được cách đây 04 năm sư phụ Ndu mới bắt đầu VBA mà đến bây giờ khiếp quá.
Em xin phép các thày có thể cho bọn em một số ví dụ VBA đơng giản về cái này cho bọn em tập với.

Em cảm ơn các thày rất nhiều.
 
Upvote 0
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").Ofset(i,0).value = kq
next i
range("sheet1!B1").value = kq
end sub
Sao em làm khi chạy nó lại báo lỗi 438 ah?
 
Upvote 0
Xem lại chữ Offset, có 2 chữ f nha
Ngoài ra còn cái khá quan trọng: Code này chưa có động tác khai báo biến
Em mới quen nên chưa biết nhiều về cái này, thày sửa dùm em chút ah.

Trước kia em cứ đọc sách của Thày Hướng nhưng thấy mông lung quá, chủ yếu là không có thời gian để thực hành nên không thâu tóm được vấn đề, Có khi nhờ tò mò từ ví dụ này sau khi hiểu rồi, tự nghĩ ra các tình huống thay đổi đầu vào có khi em lại thích học VBA.

Lần này em dự kiến bỏ hẳn 2 tháng nghiên cứu mấy cái vòng lặp này xem có nên cơm cháo gì không?
 
Upvote 0
Em mới quen nên chưa biết nhiều về cái này, thày sửa dùm em chút ah.
Thì vầy thôi:
PHP:
Private Sub Cmb1_click()
  Dim num As Long, kq As Long, i As Long
  num = Range("sheet1!A1").Value
  Range("sheet1!A2:A100").Clear
  kq = 1
  For i = 1 To num
    kq = kq * i
    Range("sheet1!A1").Offset(i).Value = kq
  Next i
  Range("sheet1!B1").Value = kq
End Sub
Để chạy code này, bạn gõ số gì đó vào cell A1 rồi bấm nút nhé
 
Upvote 0
Thì vầy thôi:
PHP:
Private Sub Cmb1_click()
  Dim num As Long, kq As Long, i As Long
  num = Range("sheet1!A1").Value
  Range("sheet1!A2:A100").Clear
  kq = 1
  For i = 1 To num
    kq = kq * i
    Range("sheet1!A1").Offset(i).Value = kq
  Next i
  Range("sheet1!B1").Value = kq
End Sub
Để chạy code này, bạn gõ số gì đó vào cell A1 rồi bấm nút nhé
Em nghĩ kq là hệ quả phép tính của đầu vào, em đã thử không cần khai báo nó cũng vẫn ra kết quả, vậy khai báo cụ thể nó trong trường hợp này có khác gì không khai báo hả thày. tức là em chỉ khai báo hai thằng num và i thôi.
PHP:
Dim num As Long,i As Long
 
Upvote 0
Em nghĩ kq là hệ quả phép tính của đầu vào, em đã thử không cần khai báo nó cũng vẫn ra kết quả, vậy khai báo cụ thể nó trong trường hợp này có khác gì không khai báo hả thày. tức là em chỉ khai báo hai thằng num và i thôi.
PHP:
Dim num As Long,i As Long
Có máy ta không khai báo biến thì code báo lỗi, có máy chẳng cần khai báo biến cũng không có vấn đề gì. Tất cả là do thiết lập trong Options
Trong cửa sổ VBE, vào menu Tools\Options, tab Editor, check mục "Request Variables Declaration".

untitled.JPG


Từ bây giờ, nếu không khai báo biến là lỗi xuất hiện liền
Nói chung khuyên mọi người nên khai báo biến đàng hoàng, sẽ có rất nhiều cái lợi, chẳng hạn:
- Được hổ trợ gợi ý bằng Tooltip khi gõ dấu chấm sau biến. Ví dụ:

untitled2.JPG


- Khai báo biến sẽ được lợi về tốc độ vì bộ nhớ sẽ được xác định chính xác
 
Upvote 0
Em nghĩ kq là hệ quả phép tính của đầu vào, em đã thử không cần khai báo nó cũng vẫn ra kết quả, vậy khai báo cụ thể nó trong trường hợp này có khác gì không khai báo hả thày. tức là em chỉ khai báo hai thằng num và i thôi.
PHP:
Dim num As Long,i As Long
Mình nên khai báo biến để quản lý một cách chặt chẽ hơn, do ngôn ngữ VB cho phép bạn không khai báo biến mà vẫn sài được, nhưng bạn đừng tưởng như vậy sẽ dễ sử dụng, bạn sẽ gặp nhiều rắc rối về nó đó, nên nhớ rằng bất cứ người nào là dân lập trình thì họ cần điều đầu tiên là rõ ràng về các biến và cách khai báo như thế nào cho hợp lý nhât
tôi nghĩ trong VB nên có câu lệnh này Option Explicit nó sẽ kiểm tra và báo lỗi nếu biến nào đã xài mà chưa khai báo
 
Upvote 0
Cảm ơn bạn... Giãi thích thế thì tôi hiểu rồi... (giống giống như khi tôi test công thức, thường hay dùng cột phụ đễ thử name và công thức mãng)... hi... hi... Rất thú vị... Tôi xem đây như là 1 cái mẹo...
Mong bạn post thêm nhiều bài khác nữa... Qua những ví dụ của bạn và các câu đố của anh SA_DQ, tôi đã tự làm dc 1 vòng lập FOR đầu tiên cho mình rồi.. ha.. ha.. Quá đã... Có thể các bạn chuyên gia trong lĩnh vực lập trình sẽ cười thầm "Ối dào, thế mà cũng mừng..." nhưng xin thưa: Cái mình chưa biết luôn là cái mới.. Và từ việc học, đến hiểu dc, rồi làm dc phải trải qua rất nhiều thử thách... Khi 1 sản phẩm đầu tiên ra lò, dù là sản phẩm ko có giá trị với mọi người đi chăng nữa, nhưng là chính tay ta làm ra nó mới cảm thấy thú vị biết dường nào... Và người dạy mình làm ra sản phẩm cũng sẽ thú vị ko kém, có phải ko? (tôi nghĩ vậy)
Một lần nữa chân thành cảm ơn sự trợ giúp của bạn!
Mến
ANH TUẤN

Hi hi, chắc mấy năm trước thày Ndu trình độ chắc ở mức chỉ cao hơn mình bây giờ 1 bậc thôi nhỉ...(em trêu thôi chứ em hầu như chưa biết gì nhiều ngoài mấy cái hàm đơn giản)
Chính những cái trao đổi của các thày như vậy em thấy rất cần thiết. Em xin hứa sẽ nỗ lực tiếp thu kiến thức của các thày để một ngày nào đó có thể giúp cho mọi người trên diễn đàn ah.

Em cảm ơn các thày rất nhiều.
 
Lần chỉnh sửa cuối:
Upvote 0
Hi hi, chắc mấy năm trước thày Ndu trình độ chắc ở mức chỉ cao hơn mình bây giờ 1 bậc thôi nhỉ...(em trêu thôi chứ em hầu như chưa biết gì nhiều ngoài mấy cái hàm đơn giản)
Chính những cái trao đổi của các thày như vậy em thấy rất cần thiết. Em xin hứa sẽ nỗ lực tiếp thu kiến thức của các thày để một ngày nào đó có thể giúp cho mọi người trên diễn đàn ah.

Em cảm ơn các thày rất nhiều.
Không ngại nói thật, lúc bước chân vào GPE, hành trang của tôi chỉ có mỗi hàm VLOOKUP (là bự nhất). Sau thời gian "cày" với mấy công thức, hiểu thêm được 1 ít, tôi bắt đầu quyết định tiến thêm 1 bước trên con đường lập trình VBA (với sự dẫn dắt của sư phụ ptm0412). Lúc ấy, hành trang về VBA của tôi là con số 0 to tướng.
Vậy tính ra thì cái thằng TUI hồi ấy còn thua bạn bây giờ ấy chứ
Bạn cũng sẽ ĐƯỢC nếu cố gắng "cày"
Ẹc... Ẹc...
 
Upvote 0
sao mình chép code vô rùi chạy ko được
 
Upvote 0
Public Sub qk()
Dim a As Range, b As Range, c As Range, i As Single, K As Integer
Set a = Range("a1:a1000")
Set b = Range("b1:b1000")
Set c = Range("c1:c1000")
For K = 1 To 100
K = K + 1
Cells(K, 2).Formula = Cells(K, 1).Value * 1
Next K
For i = 1 To 10 Step 0.1
iTOTAL = iTOTAL + i
Cells(K, 2).Formula = Cells(K, 1).Value * i
Next i
If Cells(K, 2).Value < Cells(K, 3).Value Then
Cells(K, 2).Value = Cells(K, 3).Value
Else
Cells(K, 2).Value = Cells(K, 2).Value
End If
End Sub
code này em chạy ko được
nó chỉ lập có vòng đầu tiên ....
 
Upvote 0
Public Sub qk()
Dim a As Range, b As Range, c As Range, i As Single, K As Integer
Set a = Range("a1:a1000")
Set b = Range("b1:b1000")
Set c = Range("c1:c1000")
For K = 1 To 100
K = K + 1
Cells(K, 2).Formula = Cells(K, 1).Value * 1
Next K
For i = 1 To 10 Step 0.1
iTOTAL = iTOTAL + i
Cells(K, 2).Formula = Cells(K, 1).Value * i
Next i
If Cells(K, 2).Value < Cells(K, 3).Value Then
Cells(K, 2).Value = Cells(K, 3).Value
Else
Cells(K, 2).Value = Cells(K, 2).Value
End If
End Sub
code này em chạy ko được
nó chỉ lập có vòng đầu tiên ....
Tôi đã hỏi bạn vấn đề này tại đây:
http://www.giaiphapexcel.com/forum/showthread.php?650-Chập-chững-đến-VBA!&p=381016#post381016
Sao bạn không trả lời mà post bài lung tung thế
 
Upvote 0
tui lặp cái này hoài ko được,có ai chỉ dùm
lập 3 vòng mà nó thực thi co 1 vòng đầu
thanks
 

File đính kèm

Upvote 0
Cảm ơn sư phụ nhiều...
Em tìm sư phụ để học cái môn VBA này...mà không ai mở lớp dạy hết...
Sư phụ có dạy hay có biết ai dạy chỉ cho đệ tử để đi học với...
Thanks
 
Upvote 0
tui lặp cái này hoài ko được,có ai chỉ dùm
lập 3 vòng mà nó thực thi co 1 vòng đầu
thanks
Bạn đang hỏi đến macro nào vậy? qq hay qk? Vì trong cả 2 sub này đều không có 3 vòng For. Bạn nói rõ lại chỗ này nhé.
Xin có một vài góp ý với bạn:
1. Bạn trình bày code quá xấu: Với cách trình bày suôn đuồn đuột như vậy, nếu bạn viết code dài thì rất khó kiểm soát lỗi soạn thảo. Hãy biết sử dụng phím tab khi soạn code: những lệnh nào cùng cấp thì thẳng cột với nhau, kiểu như cấu trúc cây thư mục vậy đó.
2. Trong sub qk, vòng lặp For đầu tiên (For K=0 to 100) có câu lệnh K=K+1, như vậy là không nên chút nào. Nếu bạn muốn K tăng với bước nhảy 2 đơn vị thì hãy dùng For K=0 To 100 Step 2, còn nếu bạn muốn K tăng 1 đơn vị thì không cho câu lệnh K=K+1 vào vì sẽ làm cho vòng For chạy không đúng số lần lặp. Như vậy, trong mọi trường hợp, không dùng câu lệnh làm thay đổi giá trị biến chạy trong vòng For.
3. Trong sub qq, bạn có dùng câu này:
PHP:
If b < c Then
b = b
Else
b = c
End If
Câu lệnh này có vẻ thừa quá. Gán b=b thì gán làm gì? Bạn có thể sử dụng: If b>=c then b=c.
 
Lần chỉnh sửa cuối:
Upvote 0
cảm ơn anh nghỉa phúc ,em sửa lại code bỏ vòng lập k = 1 to 100
thì code báo lỗi chạy không được...code kq
Anh sửa giúp em nhé
Thanks
Public Sub qk()
Dim a As Range, b As Range, c As Range, i As Single, K As Integer
Sheet2.Active
For K = 1 To 100
Cells(K, 2).Formula = Cells(K, 1).Value * i
K = K + 1
Next K
Cells(K, 2).Active
For i = 1 To 10 Step 0.1
itotal = itotal + 1
Cells(K, 2).Formula = Cells(K, 1).Value * i
Next i
If Cells(K, 2).Value < Cells(K, 3).Value Then
Cells(K, 2).Value = Cells(K, 3).Value
Else
Cells(K, 2).Value = Cells(K, 2).Value
End If
End Sub
 
Upvote 0
cảm ơn anh nghỉa phúc ,em sửa lại code bỏ vòng lập k = 1 to 100
thì code báo lỗi chạy không được...code kq
Anh sửa giúp em nhé
Thanks
Public Sub qk()
Dim a As Range, b As Range, c As Range, i As Single, K As Integer
Sheet2.Active
For K = 1 To 100
Cells(K, 2).Formula = Cells(K, 1).Value * i
K = K + 1
Next K
Cells(K, 2).Active
For i = 1 To 10 Step 0.1
itotal = itotal + 1
Cells(K, 2).Formula = Cells(K, 1).Value * i
Next i
If Cells(K, 2).Value < Cells(K, 3).Value Then
Cells(K, 2).Value = Cells(K, 3).Value
Else
Cells(K, 2).Value = Cells(K, 2).Value
End If
End Sub
Trình bày lại code của bạn một chút cho dễ nhìn nhé (hãy sử dụng tag
PHP:
[ /PHP] hoặc [CODE][ /CODE] để trình bày code cho dễ nhìn):
[code]Public Sub qk()
    Dim a As Range, b As Range, c As Range, i As Single, K As Integer
    Sheet2.[COLOR=#ff0000]Active[/COLOR]
    For K = 1 To 100
        Cells(K, 2)[COLOR=#ff0000].Formula[/COLOR] = Cells(K, 1).Value [COLOR=#ff0000]* i
[/COLOR]        [COLOR=#ff0000]K = K + 1
[/COLOR]    Next K
    Cells(K, 2).[COLOR=#ff0000]Active[/COLOR]
    For i = 1 To 10 Step 0.1
        itotal = itotal + 1
        Cells(K, 2).Formula = Cells(K, 1).Value * i
    Next i
    If Cells(K, 2).Value < Cells(K, 3).Value Then
        Cells(K, 2).Value = Cells(K, 3).Value
    [COLOR=#ff0000]Else
        Cells(K, 2).Value = Cells(K, 2).Value
    End If
[/COLOR]End Sub[/code]
Trong code có một số vấn đề sau:
1. Không có phương thức Active, đúng ra là Activate.
2. Mấy chỗ .Formula, .Value có thể bỏ vì thuộc tính Value là thuộc tính mặc định của cell.
3. Ở vòng For của K, bạn lại cho câu lệnh K=K+1 vào, vậy là bạn không đọc bài trên. Thêm nữa, giá trị của i ban đầu là 0 nên câu lệnh có *i ở trong vòng For này sẽ cho kết quả ở cột B luôn là 0.
3. Chỗ Else... màu đỏ trên là thừa, câu lệnh If này có thể thay bởi câu lệnh:
[PHP]Cells(K, 2) = WorksheetFunction.Max(Cells(K, 2), Cells(K, 3))
hoặc để nguyên câu lệnh If như của bạn, bỏ Else... và xóa dấu xuống dòng sau Then.
4. Trong 2 vòng For (của K và của i) thì Cells(K, 2) là khác nhau đấy nhé: Trong vòng For của K thì đây là những ô khác nhau (do K thay đổi), còn trong vòng For của i thì đây là 1 ô cố định vì lúc này K không thay đổi nữa.
Tóm lại là code của bạn còn nhiều vấn đề, và đến bây giờ thì mình vẫn chưa hiểu là bạn muốn code này làm việc gì cả. Hãy mô tả về yêu cầu cụ thể, mọi người sẽ giúp bạn xây dựng code phù hợp. Sau đó, bạn có thể hỏi họ về các câu lệnh trong code. Đây cũng là một cách học code theo kiểu "đi tắt đón đầu" đó bạn.
 
Upvote 0
Đoạn code này có ý nghĩa như thế nào , xin các bạn giải thích giùm.cảm ơn.Tong1 = Cells(i, 1).Value + Cells(i + 1, 1).Value + Cells(i + 2, 1).Value
 
Upvote 0
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").Ofset(i,0).value = kq
next i
range("sheet1!B1").value = kq
end sub

Em xin chào mọi người, em đã làm y chang như vậy rồi mà vẫn báo lỗi ở dòng thứ 7:
Range("sheet1!A1").Ofset(i, 0).Value = kq
Có ai giải thích dùm em với. Cảm ơn mọi người.
 
Lần chỉnh sửa cuối:
Upvote 0
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").Ofset(i,0).value = kq
next i
range("sheet1!B1").value = kq
end sub

Em xin chào mọi người, em đã làm y chang như vậy rồi mà vẫn báo lỗi ở dòng thứ 7:
Range("sheet1!A1").Ofset(i, 0).Value = kq
Có ai giải thích dùm em với. Cảm ơn mọi người.
1. Sao không thử viết thế này num= Sheets("Sheet1").Range("A1").value
2. Sửa Ofset thành Offset
 
Upvote 0
Câu lệnh này hơi kỳ
PHP:
Range("sheet1!A1:A100").clear
Thông thường mình thấy mọi người hay viết

sheet1!Range("A1:A100").clear (Đúng là câu này mình viết sai chính tả; Fải là vầy: Sheet1.Range("A1:A100").clear)
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
sheets("sheet1").Range("A1:A100").Clear
sheet1.Range("A1:A100").Clear
Range("sheet1!A1:A100").Clear
...
tất cả đều đúng
Cứ nghiên cứu cho kỹ cái câu "tất cả đều đúng" đi nhé. Thử thay Sheet1 thành Sheet2 đi rồi xem có dám nói tất cả đều đúng hay không.
 
Upvote 0
Cứ nghiên cứu cho kỹ cái câu "tất cả đều đúng" đi nhé. Thử thay Sheet1 thành Sheet2 đi rồi xem có dám nói tất cả đều đúng hay không.
Sheet1.Range, Sheet2.Range Là thứ tự trong sheet chứ không phải tên sheet nha anh Hải, từ trước tới giờ em chưa thấy lỗi, anh Hải có thể cho em ví dụ 1 trường hợp lỗi được không. để em biết mà tránh, cảm ơn anh nhiều, tham gia trả lời bài vừa thấy vui là giúp được người hỏi, và vừa thấy vui là được học hỏi từ nhiều người ấy
Picture1.jpg
 
Lần chỉnh sửa cuối:
Upvote 0
Sheet1.Range, Sheet2.Range Là thứ tự trong sheet chứ không phải tên sheet nha anh Hải, từ trước tới giờ em chưa thấy lỗi, anh Hải có thể cho em ví dụ 1 trường hợp lỗi được không. để em biết mà tránh, cảm ơn anh nhiều, tham gia trả lời bài vừa thấy vui là giúp được người hỏi, và vừa thấy vui là được học hỏi từ nhiều người ấy
View attachment 135133
Chạy được là may mắn thôi.
Thử vẽ cái CommandButton và cho code vào test sẽ thấy sự khác nhau liền.
 
Upvote 0
sheets("sheet1").Range("A1:A100").Clear
sheet1.Range("A1:A100").Clear
Range("sheet1!A1:A100").Clear
...
tất cả đều đúng

Dòng màu đỏ
không bao giờ tương đương với 2 dòng màu xanh đâu nha
Một đằng là Sheet CodeName, một đằng là Sheet Name ---> Chẳng ăn nhậu gì nhau cả
 
Upvote 0
Upvote 0

Dòng màu đỏ
không bao giờ tương đương với 2 dòng màu xanh đâu nha
Một đằng là Sheet CodeName, một đằng là Sheet Name ---> Chẳng ăn nhậu gì nhau cả
anh có thể giải thích cho em sự khác biệt giữa dòng màu xanh và màu đỏ được không. từ trước tới giờ em toàn sử dụng sheet1.range không hà, em cảm ơn anh nhiều
 
Upvote 0
Trong hình của bạn sheet1 (A) thì
- Sheet1 là codename là thuộc tính readonly, không sửa được, do excel tự tạo. Sử dụng sheet1.range("A1")
- A là name, có thể thay đổi chỉnh sửa. Sử dụng sheets("A").range("A1"). Bình thường sheet1(sheet1) bạn có thể sửa name thành sheet1(sheet2)
-Ngoài ra còn có thể dùng số thứ tự của sheet: sheets(1) là sheet ngoài cùng bên trái, sheets(2) là sheet thứ 2.
 
Lần chỉnh sửa cuối:
Upvote 0
ý của mình là muốn biết sử dụng các trường hợp đó khi nào sẽ bị khác nhau và bị sai thôi
Trong hình của bạn sheet1 (A) thì
- Sheet1 là codename là thuộc tính readonly, không sửa được, do excel tự tạo. Sử dụng sheet1.range("A1")
Cái này là xem lại nha, vì 3 năm nay mình hay sửa cái này và áp dụng rất tốt
Picture2.jpg
Sheet1 là codename đã đuợc đổi tên thành AA
 
Lần chỉnh sửa cuối:
Upvote 0
ý của mình là muốn biết sử dụng các trường hợp đó khi nào sẽ bị khác nhau và bị sai thôi

Cái này là xem lại nha, vì 3 năm nay mình hay sửa cái này và áp dụng rất tốt

Sheet1 là codename đã đuợc đổi tên thành AA

Xem hình và tự suy nghĩ nhé:

Capture.JPG



































Nghĩ xem Sheet1.Range("...") có tương đương với Sheets("Sheet1").Range("...") hay không?
 
Upvote 0
Không bao giờ sai cả vì cách dùng khác nhau, nếu bình thường sheet1 (sheet1) thì
- Dùng codename: sheet1.activate, sheet1.range...
- Dùng name sheets("sheet1").activate...
ý mình muốn là sự khác biệt của nó ấy, chắc rằng là có vì các tiền bối ở đây tiếp xúc rất nhiều nên có nhiều trường hợp mà mình chưa biết, nên muốn học hỏi thêm thôi cảm ơn bạn đã quan tâm vấn đề này nha
 
Upvote 0
Xem hình và tự suy nghĩ nhé:
Nghĩ xem Sheet1.Range("...") có tương đương với Sheets("Sheet1").Range("...") hay không?
dạ cái này em biết mà, em cũng hay đổi tên lại và truy xuất như thế này
Picture2.jpg
Ý em nói là mình truy xuất AA.range..sheets("A").range... là có khác nhau hay không thôi?
 
Upvote 0
dạ cái này em biết mà, em cũng hay đổi tên lại và truy xuất như thế này
View attachment 135139
Ý em nói là mình truy xuất AA.range..sheets("A").range... là có khác nhau hay không thôi?
Không khác nhau nếu đó là file của bạn và bạn biết chắc rằng Sheet CodeName AA chính là sheet có tên là "A"
Nhưng tự nhiên mà nói rằng Sheet1.Range("...") tương đương với Sheets("Sheet1").Range("...") là SAI HOÀN TOÀN
Vậy thôi
 
Lần chỉnh sửa cuối:
Upvote 0
ý của mình là muốn biết sử dụng các trường hợp đó khi nào sẽ bị khác nhau và bị sai thôi

Cái này là xem lại nha, vì 3 năm nay mình hay sửa cái này và áp dụng rất tốt
View attachment 135136
Sheet1 là codename đã đuợc đổi tên thành AA
Đúng là có thể thay đổi trong mục (Name) ở sheet property, sh.codename không có dấu cách, nhưng dùng lệnh thì không gán được.
Còn property name ở dòng dưới là tên hiển thị trên sheet thì có thể có dấu cách (sh.name)
 
Upvote 0
Đúng là có thể thay đổi trong mục (Name) ở sheet property, sh.codename không có dấu cách, nhưng dùng lệnh thì không gán được.

Sao lại không được chứ. Ví dụ:
Mã:
Thisworkbook.VBProject.VBComponents(Thisworkbook.Sheets("Sheet1").CodeName).Name = "NDU"
Với điều kiện phải check mục "Trust Access to VBA project... " trong Excel Options
 
Upvote 0
Range("sheet1!A1").Ofset(i, 0).Value = kq
Bạn sai chỗ đậm đậm đó
Gửi bác QuangHai1969 và bác phihndhsp:
Bởi đoạn code em lấy từ bài bắt đầu của chủ topic mà. Nhưng nếu đoạn code đó sai thì không lẽ không ai phát hiện, và nó đã tồn tại cho đến bây giờ nghĩa là ban đầu là đúng, nên em mới tự đặt câu hỏi là tại sao??? bây giờ em phải thay đổi đoạn code đó cho đúng thì mới chạy được. Em mới bắt đầu nên mù mờ lắm ạ &&&%$R
 
Upvote 0
Gửi bác QuangHai1969 và bác phihndhsp:
Bởi đoạn code em lấy từ bài bắt đầu của chủ topic mà. Nhưng nếu đoạn code đó sai thì không lẽ không ai phát hiện, và nó đã tồn tại cho đến bây giờ nghĩa là ban đầu là đúng, nên em mới tự đặt câu hỏi là tại sao??? bây giờ em phải thay đổi đoạn code đó cho đúng thì mới chạy được. Em mới bắt đầu nên mù mờ lắm ạ
Bài 1 topic này tôi gõ mà không chú ý bộ gõ đang là telex, nên gõ Offset bị biến thành Ofset (1 chữ f). Phải 2 f mới đúng.
 
Upvote 0
Mình dùng for lồng for để tìm dựa trên từng số Hoá đơn trong Sheet bccn có 8000 dòng
để lấy số tiền đã thanh toán trong Sheet ZPP Phyto có 6000 dòng nếu trùng số HD để ra Sheet bccn
Khi chạy thì treo gần 16p mới chạy xong lệnh này. Cho mình hỏi có cách nào nhanh hơn không?
For i = 2 To ActiveWorkbook.Sheets("bccn").Range("D" & Rows.Count).End(xlUp).Row
SoHD = ActiveWorkbook.Sheets("bccn").Range("D" & i).Value
For j = 2 To ActiveWorkbook.Sheets("ZPP Phyto").Range("N" & Rows.Count).End(xlUp).Row
If SoHD = ActiveWorkbook.Sheets("ZPP Phyto").Range("N" & j).Value Then
ActiveWorkbook.Sheets("bccn").Range("F" & i).Value = ActiveWorkbook.Sheets("ZPP Phyto").Range("Q" & j).Value
Exit For
End If
Next j
Next i

Cảm ơn các bạn nhiều
 
Upvote 0
Mình đã xoá bớt dòng mới up được
Bạn xem giúp mình. Cảm ơn bạn

dùng mảng có thể tăng tốc được chút ít
Mã:
Sub congNo()
Application.ScreenUpdating = False
    Dim maKH, tenKH As String
    Dim tienPhaiTra, tienDaTra, congNo, tongCongNo As Currency
    Dim ngayHD As Date
    Dim SoHD As Long
    Dim bccn, zpp As Variant
    With Sheet4
        .[A:f].Clear
        .[a:b].Value = Sheet2.[e:f].Value ' MaKH ' Ten KH
        .[c:c].Value = Sheet2.[a:a].Value ' Ngay HD
        .[d:d].Value = Sheet2.[c:c].Value ' So HD
        .[e:e].Value = Sheet2.[e:e].Value ' TTien
        bccn = .[a2].Resize(.[a60000].End(xlUp).Row, 6).Value
    End With
  zpp = Sheet1.[a2].Resize(Sheet1.[p60000].End(3).Row, 17).Value
    For i = 1 To UBound(bccn)
        For j = 1 To UBound(zpp)
            If bccn(i, 4) = zpp(j, 14) Then
                bccn(i, 6) = zpp(j, 17)
                Exit For
            End If
        Next j
    Next i
    Sheet4.[a2].Resize(UBound(bccn), 6).Value = bccn
Application.ScreenUpdating = True
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Bài này dùng Dictionary sẽ nhanh thêm gấp nhiều lần
Bài này nếu các hóa đơn đã được sort như file đính kèm thì dùng mảng kết hợp vòng lặp do loop lồng trong for sẽ nhanh hơn. Do cả 2 cùng sort tăng dần nên biến đếm j của Do loop có thể sử dụng lại sau khi biến đếm i của vòng For tăng.
 
Upvote 0
Bài này dùng Dictionary sẽ nhanh thêm gấp nhiều lần

tại vì lúc đầu nghĩ là đăng nào cũng phải xài 2 vòng lặp.
đúng là theo logic thì 2 vòng lặp đơn thì sẻ nhanh hơn vòng lặp lồng vào nhau
nhưng sau khi xài dic thì nó cũng ko nhanh hơn được là bao nhiêu (test trên laptop mini cũ 19s, mới 16s). anh xem dùm xem code như vậy đã tối ưu chưa
Mã:
Sub congNo()
s_time = Now()
Application.ScreenUpdating = False
    Dim maKH, tenKH As String
    Dim tienPhaiTra, tienDaTra, congNo, tongCongNo As Currency
    Dim ngayHD As Date
    Dim SoHD, k As Long
    Dim bccn, zpp As Variant, d As Object
    Set d = CreateObject("Scripting.Dictionary")
    With Sheet4
        .[A:f].Clear
        .[a:b].Value = Sheet2.[e:f].Value ' MaKH ' Ten KH
        .[c:c].Value = Sheet2.[a:a].Value ' Ngay HD
        .[d:d].Value = Sheet2.[c:c].Value ' So HD
        .[e:e].Value = Sheet2.[e:e].Value ' TTien
        bccn = .[a2].Resize(.[a60000].End(xlUp).Row, 6).Value
    End With
  zpp = Sheet1.[a2].Resize(Sheet1.[p60000].End(3).Row, 17).Value
    For i = 1 To UBound(bccn)
        If Not d.exists(bccn(i, 4)) Then
            k = k + 1
            d.Add (bccn(i, 4)), k
        End If
    Next i
    
        For j = 1 To UBound(zpp)
            If d.exists(zpp(j, 14)) Then
                bccn(d.Item(zpp(j, 14)), 6) = zpp(j, 17)
            End If
        Next j
    
    Sheet4.[a2].Resize(UBound(bccn), 6).Value = bccn
Application.ScreenUpdating = True
MsgBox Second(Now() - s_time)
End Sub
 
Upvote 0
tại vì lúc đầu nghĩ là đăng nào cũng phải xài 2 vòng lặp.
đúng là theo logic thì 2 vòng lặp đơn thì sẻ nhanh hơn vòng lặp lồng vào nhau
nhưng sau khi xài dic thì nó cũng ko nhanh hơn được là bao nhiêu (test trên laptop mini cũ 19s, mới 16s). anh xem dùm xem code như vậy đã tối ưu chưa
Nếu đúng như giả định của mình về 2 cột số hóa đơn ở 2 sheet đều được sort thì thủ tục sau sẽ nhanh hơn nhiều (khoảng 0.07s, thủ tục của bác là 6s trên laptop Core i7, RAM 16G)
Mã:
Sub CongNo4()
    Dim bccn_D(), bccn_F(), zpp_N(), zpp_Q(), EndRow_bccn&, EndRow_zpp&, MaxRow&, i&, j&, last_j&, t
    Application.ScreenUpdating = False
    t = Timer
    With Sheets("Tong hop theo HD")
        .Columns("E:F").Copy Range("A1")
        .Columns(1).Copy Range("C1")
        .Columns(3).Copy Range("D1")
        .Columns("X").Copy Range("E1")
    End With
    Rows(1).ClearContents
    
    MaxRow = Columns(1).Rows.Count
    
    EndRow_bccn = Range("A" & MaxRow).End(xlUp).Row
    bccn_D = Range("D2:D" & EndRow_bccn)
    ReDim bccn_F(1 To EndRow_bccn - 1, 1 To 1)
    
    With Sheets("ZPP Phyto HCM Daily Customer P")
        EndRow_zpp = .Range("A" & MaxRow).End(xlUp).Row
        zpp_N = .Range("N2:N" & EndRow_zpp).Value
        zpp_Q = .Range("Q2:Q" & EndRow_zpp).Value
    End With
    last_j = 1
    For i = 1 To EndRow_bccn - 1
        j = last_j
        Do While j < EndRow_zpp
            If bccn_D(i, 1) < zpp_N(j, 1) Then Exit Do
            If bccn_D(i, 1) = zpp_N(j, 1) Then
                bccn_F(i, 1) = zpp_Q(j, 1)
                last_j = j
                Exit Do
            End If
            j = j + 1
        Loop
    Next
    
    Range("F2:F" & EndRow_bccn) = bccn_F
    Application.ScreenUpdating = True
    MsgBox Timer - t
End Sub
 
Upvote 0
tại vì lúc đầu nghĩ là đăng nào cũng phải xài 2 vòng lặp.
đúng là theo logic thì 2 vòng lặp đơn thì sẻ nhanh hơn vòng lặp lồng vào nhau
nhưng sau khi xài dic thì nó cũng ko nhanh hơn được là bao nhiêu (test trên laptop mini cũ 19s, mới 16s). anh xem dùm xem code như vậy đã tối ưu chưa
Mã:
Sub congNo()
s_time = Now()
Application.ScreenUpdating = False
    Dim maKH, tenKH As String
    Dim tienPhaiTra, tienDaTra, congNo, tongCongNo As Currency
    Dim ngayHD As Date
    Dim SoHD, k As Long
    Dim bccn, zpp As Variant, d As Object
    Set d = CreateObject("Scripting.Dictionary")
    With Sheet4
        .[A:f].Clear
        .[a:b].Value = Sheet2.[e:f].Value ' MaKH ' Ten KH
        .[c:c].Value = Sheet2.[a:a].Value ' Ngay HD
        .[d:d].Value = Sheet2.[c:c].Value ' So HD
        .[e:e].Value = Sheet2.[e:e].Value ' TTien
        bccn = .[a2].Resize(.[a60000].End(xlUp).Row, 6).Value
    End With
  zpp = Sheet1.[a2].Resize(Sheet1.[p60000].End(3).Row, 17).Value
    For i = 1 To UBound(bccn)
        If Not d.exists(bccn(i, 4)) Then
            k = k + 1
            d.Add (bccn(i, 4)), k
        End If
    Next i
    
        For j = 1 To UBound(zpp)
            If d.exists(zpp(j, 14)) Then
                bccn(d.Item(zpp(j, 14)), 6) = zpp(j, 17)
            End If
        Next j
    
    Sheet4.[a2].Resize(UBound(bccn), 6).Value = bccn
Application.ScreenUpdating = True
MsgBox Second(Now() - s_time)
End Sub
Cảm giác hình như bạn làm ngược thì phải? Lý ra phải lấy dữ liệu từ cột N của sheet "ZPP Phyto HCM Daily Customer P" để nạp vào Dictionary chứ nhỉ?
----------------
Tôi làm thế này:
Mã:
Sub Main()
  Dim dic As Object
  Dim n As Long
  Dim tmp1 As String
  Dim tmp2 As Double, t As Double
  Dim aSrc, aDes, aTitle
  Dim wks1 As Worksheet, wks2 As Worksheet, wks3 As Worksheet
  t = Timer
  aTitle = Array("Ma_KH", "Ho_Ten", "Ngay", "So_Phieu", "Ma_KH")
  Set wks1 = Worksheets("Tong hop theo HD")
  Set wks2 = Worksheets("ZPP Phyto HCM Daily Customer P")
  Set wks3 = Worksheets("temp bccn")
  With wks3
    .Range("A1:E1").Value = aTitle
    wks1.Range("A1:F10000").AdvancedFilter 2, , .Range("A1:E1")
  End With
  aSrc = wks2.Range("N2:Q10000").Value
  aDes = wks3.Range("D2:D10000").Value
  ReDim arr(1 To UBound(aDes, 1), 1 To 1)
  Set dic = CreateObject("Scripting.Dictionary")
  dic.CompareMode = vbTextCompare
  For n = 1 To UBound(aSrc, 1)
    tmp1 = CStr(aSrc(n, 1))
    tmp2 = CDbl(aSrc(n, 4))
    If Len(tmp1) Then
      If Not dic.Exists(tmp1) Then dic.Add tmp1, tmp2
    End If
  Next
  For n = 1 To UBound(aDes, 1)
    tmp1 = CStr(aDes(n, 1))
    If Len(tmp1) Then
      If dic.Exists(tmp1) Then arr(n, 1) = dic.Item(tmp1)
    End If
  Next
  wks3.Range("F2:F10000").Value = arr
  MsgBox Timer - t
End Sub
Đoán đại, làm bừa, cũng chưa chắc trúng
Ẹc... Ẹc...
 
Lần chỉnh sửa cuối:
Upvote 0

em có bài toán vòng lặp như hình trên.
cách làm của em là
for i = ... to ..... step 7' quet du lieu cot A
Rng1.copy => copy dữ liệu ứng với nguyen van a, nguyen van b, nguyen van c ....
for j = ... to ... step 7 ' quet tim vi tri cot G (hoac H) de paste
.paste => paste du lieu tuong ung voi nguyen van a, nguyen van b, nguyen van c vao cac vi tri cua cot G (hoac H deu duoc) giữ nguyên định dạng
next
next
nói chung là bài toán được giải
em hỏi là có cách nào tăng tốc hơn để giải quyết bài toán trên khi mà dữ liệu lên đến vài chục nghìn dòng thì lâu quá.
bài toán mở rộng lên khi cột F nằm trong sheet khác nữa.
Trân trọng cảm ơn.
Đọc từ đầu đến cuối bài vòng lặp for .... next phần đầu em còn hiểu tí tí, phần sau thì mù tịt
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
em có bài toán vòng lặp như hình trên.
cách làm của em là

nói chung là bài toán được giải
em hỏi là có cách nào tăng tốc hơn để giải quyết bài toán trên khi mà dữ liệu lên đến vài chục nghìn dòng thì lâu quá.
bài toán mở rộng lên khi cột F nằm trong sheet khác nữa.
Trân trọng cảm ơn.
Đọc từ đầu đến cuối bài vòng lặp for .... next phần đầu em còn hiểu tí tí, phần sau thì mù tịt
+ Nhìn hình minh họa của bạn tôi vẫn chưa hiểu lắm! Bạn có thể nói rõ hơn yêu cầu của bạn 1 chút được không?
+ Bạn có thể đưa dữ liệu thực tế hơn 1 chút được ko? Chỉ cần tên của 3 người cũng được kèm kết quả mong muốn vào file nữa nhé!
 
Lần chỉnh sửa cuối:
Upvote 0

em có bài toán vòng lặp như hình trên.
cách làm của em là

nói chung là bài toán được giải
em hỏi là có cách nào tăng tốc hơn để giải quyết bài toán trên khi mà dữ liệu lên đến vài chục nghìn dòng thì lâu quá.
bài toán mở rộng lên khi cột F nằm trong sheet khác nữa.
Trân trọng cảm ơn.
Đọc từ đầu đến cuối bài vòng lặp for .... next phần đầu em còn hiểu tí tí, phần sau thì mù tịt

Nếu chỉ lấy giá trị thì đưa vào mảng, gán xuống sheet 1 lần là nhanh nhất.
Bạn lại muốn copy "y chang" cả định dạng thì phải lâu rồi.
Thử xem cái này.
PHP:
Public Sub GPE()
Application.ScreenUpdating = False
Dim I As Long, J As Long, Rws As Long, R As Long
R = 1
Rws = Range("A65536").End(xlUp).Row
For I = 1 To Rws Step 7
    For J = 1 To 3
        Range("A" & I).Resize(7, 2).Copy Range("F" & R)
        Range("H" & R).Value = "tien" & J
        R = R + 7
    Next J
Next I
End Sub
Nếu mở rộng cột F sang "sheet khác" thì thay .Copy Range("F" & R) thành .Copy "sheet khác". Range("F" & R).
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
em có bài toán vòng lặp như hình trên.
cách làm của em là
................................................................
nói chung là bài toán được giải
em hỏi là có cách nào tăng tốc hơn để giải quyết bài toán trên khi mà dữ liệu lên đến vài chục nghìn dòng thì lâu quá.
bài toán mở rộng lên khi cột F nằm trong sheet khác nữa.
Trân trọng cảm ơn.
Đọc từ đầu đến cuối bài vòng lặp for .... next phần đầu em còn hiểu tí tí, phần sau thì mù tịt
tôi dùng 1 vòng lặp thôi. Bạn xem thế nào do ko rõ yêu cầu của bạn nên tỉ lệ làm sai rất cao! Có gì hồi âm lại ngay nhé!
 

File đính kèm

Upvote 0
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

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
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

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

Back
Top Bottom