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,804
Được thích
36,315
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:
anhtuan1066 đã viết:
Tôi áp dụng vòng lập FOR cho việc tô màu chử theo điều kiện... Code chạy tốt, tuy nhiên khi tôi kết hợp với ComboBox đễ lấy chuổi cần tìm từ nó thì chẳng hiểu sao nó lại ko cập nhật kịp thời... Ví dụ tôi gõ chử Q vào ComboBox, tôi phải gõ chử Q thêm lần thứ 2 thì mới thấy code chạy
Các bạn xem file và sửa giùm với!
ANH TUẤN

Sai chỗ này:
Mã:
Tu = UCase(Range("F1").Value) 'Tu can tim
Range("F1").Value = ComboBox1
dòng 1 biến Tu lấy giá trị cũ từ F1, dòng 2 mới cập nhật F1 từ ComboBox1. Nên đảo thứ tự 2 câu trên lại để lấy giá trị thay đổi từ ComboBox trước khi ghi vào biến Tu:
Mã:
Range("F1").Value = ComboBox1
Tu = UCase(Range("F1").Value) 'Tu can tim
 
Upvote 0
Cảm ơn... chạy dc rồi... nhưng còn 1 rắc rối nữa đối với Number... Ví dụ gõ vào số 5 nó tô màu tầm bậy chẳng đúng gì cả...
Lý do tại sao nhỉ?

ôi... tôi thử kỹ rồi... Hình như ko có giãi pháp cho trường hợp cell là Number thì phải... Thí nghiệm bằng cách gõ vào 1 cell nào đó số 123456 chẳng hạn thì ko có cách nào tô màu từng số dc.. ví dụ tô kiểu 123456
Chỉ còn có nước chuyển toàn bộ dử liệu cái nào là Number sang Text... Nhưng điều này lại gây khó khăn cho việc tính toán... Hic...
ANH TUẤN
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
ThuNghi đã viết:
Lá thư này viết trện Excel? Text Box hay là?
Vậy viết for... trên word?
Các Bác làm em xấu hổ quá. Lâu lâu nổi hứng văn chương bậy bạ bị bắt gặp. Cứ viết như thế này là được rồi:
Cho 1 câu văn dài ở cell A1 và 1 từ ở cell A2, đếm....
Rủi ai có lá thư thật trong word mà không biết copy paste vào thì mình mang tội với trời đất.
 
Upvote 0
Tôi áp dụng vòng lập FOR cho việc tô màu chử theo điều kiện... Code chạy tốt, tuy nhiên khi tôi kết hợp với ComboBox đễ lấy chuổi cần tìm từ nó thì chẳng hiểu sao nó lại ko cập nhật kịp thời... Ví dụ tôi gõ chử Q vào ComboBox, tôi phải gõ chử Q thêm lần thứ 2 thì mới thấy code chạy
Các bạn xem file và sửa giùm với!
- oh, sao atuan... ko dùng textbox mà lại dùng commbobox nhỉ??? chỉ khi có nhiều giá trị lựa chọn thì ng ta mới dùng combobox

- atuan... làm thế này, ng khác học for cơ bản làm sao theo kịp ... hic

- Ah function thì cũng tương tự sub thôi, nhưng nó tiện lợi là trả về 1 giá trị và có thể nhập các tham số cho Function, và có ở thường ở cuối trước "End Function" có lệnh gán <tên hàm"> =<giá trị>, thế thôi,
đơn giản và tiện ích vì Function luôn động với dữ liệu (giống hàm của Excel) trong khi đó sub chỉ thực hiện khi chạy.

Cho 1 dãy số thực n phần tử (được chứa vào các ô của 1 cột - chẳng hạn 10 số từ A1,A2,...,A10).
Tìm 3 phần tử liên tiếp mà có tổng là max nhất (tổng 3 phần tử này)?


Vd dãy số 3 4 5 8 1 6 7 6 5 2
kQ: 3 phần tử cần tìm là 6 7 6 có tổng =19

Mở rộng: Tìm 5,7,...,hay k phần tử liên tiếp (k<n - nhập từ 1 ô nào đó) có tổng max

các BẠN thử giải xem
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Lần chỉnh sửa cuối:
Upvote 0
Bài của TigerTiger tôi giãi như sau:
Mã:
Sub TongMax()
Dim Tong As Integer
Dim Tong1 As Integer
Dim Ki As Integer
For i = 1 To 8
    Tong1 = Cells(i, 1).Value + Cells(i + 1, 1).Value + Cells(i + 2, 1).Value
    If Tong < Tong1 Then
       Tong = Tong1
       Ki = i
    End If
Next i
Range("B1").Value = "3 so lien tiep can tim la"
Range("C1").Value = Cells(Ki, 1).Value
Range("C2").Value = Cells(Ki + 1, 1).Value
Range("C3").Value = Cells(Ki + 2, 1).Value
Range("B4").Value = "Tong la"
Range("C4").Value = Tong
End Sub
-------------------
Với bài mở rộng tôi đang mường tượng sẽ có thêm 1 vòng lập nữa quét theo K đễ tính TONG1... nhưng tạm thời chưa nghĩ ra dc giãi thuật.. chắc cũng ko đến nỗi khó lắm nhỉ? Hi.. hi..
ANH TUẤN

Tôi làm dc bài toán dạng tổng quát rồi, ko cần thêm vòng lập gì cả (bám vào điều kiện số liên tiếp)
PHP:
Sub TongMax()
Dim Tong As Integer
Dim Tong1 As Integer
Dim Ki As Integer
Dim Soo As Integer
Dim Er As Integer
Soo = Range("D1").Value
Er = Range("A1000").End(xlUp).Row
Columns("C:C").ClearContents
Range("B1").ClearContents
If Soo > Er Then
MsgBox "Nhap so nho hon " & Er
Range("D1").ClearContents
Exit Sub
End If
For i = 1 To Er - Soo + 1
Tong1 = Application.WorksheetFunction.Sum(Range("A" & i & ":A" & i + Soo - 1))
If Tong < Tong1 Then
Tong = Tong1
Ki = i
End If
Next i
Range("B1").Value = "Tong can tim la " & Tong
Range("C1:C" & Soo).Value = Range("A" & Ki & ":A" & Ki + Soo - 1).Value
End Sub
File đính kèm ở đây! Mọi người xem thử có gì ko ổn ko? Tôi test thấy chạy tốt và chưa phát hiện lỗi nào cả!
Mến
ANH TUẤN
 

File đính kèm

  • TongMax.zip
    8.6 KB · Đọc: 101
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Oh, atuan... giải nhanh quá

chỉ có mấy ý kiến góp ý với a thôi:

1) Đoạn lệnh sau
anhtuan1066 đã viết:
PHP:
 For i = 1 To Er - Soo + 1
Tong1 = Application.WorksheetFunction.Sum(Range("A" & i & ":A" & i + Soo - 1))
If Tong < Tong1 Then
Tong = Tong1
Ki = i
End If
Next i
Giá trị của biến Tong chưa được tính / gán, vì thế nó sẽ có giá trị mặc định sau khi khai báo là 0. Vậy giả định nếu dãy số của chúng ta có các số âm hay đặc biệt toàn âm tưc là khi đó có thể Tong1 dù max nhất cũng <0 thì khi đó kết quả sẽ ko có ->sai vì đ/k Tong < Tong1 ko xảy ra. Giải pháp cho vấn đề là chúng ta nên tính Tong trước có nghĩa là trước lệnh vòng For thêm dòng lệnh sau, và chỉ số của vòng for sẽ bắt đầu từ 2:
PHP:
 Tong1 = Application.WorksheetFunction.Sum(Range("A1:A" & Soo))
For i = 2 To Er - Soo + 1
  <........>
2)

anhtuan1066 đã viết:
....., ko cần thêm vòng lập gì cả (bám vào điều kiện số liên tiếp)
tigertiger thiết nghĩ: Nên dùng vòng for để tính Tong1 để tính cho tổng quảt; Thường thì để chương trình nhanh hơn chúng ta nên hạn chế số lần đọc số liệu từ ô (cell) của bảng tính. trong Sub của atuan thì sẽ những ô sẽ phải truy xuất dữ liệu đến Soo lần, vì thế nên:
+ tạo 1 biến mảng -> đọc số liệu dãy số từ các cell chỉ một lần vào biến mảng này -> rồi chương trình xử lý biến mảng này
+ Dĩ nhiên khi đó không dùng được hàm SUM của Excel nữa -> ta phải dùng thêm 1 vòng FOR tính tổng (đang nói về for - chúng ta cũng cố gắng dùng for chứ...)
VD:
PHP:
Dim DaySo() as Double

<...........>

'sau khi xác định được Er -> khai báo độ lượng thực của mảng DaySo

ReDim DaySo(Er)

'Nhập dãy số từ các ô cho mảng
For i = 1 To Er
   DaySo(i) = Range("A" & i).Value
Next i
và đoạn tìm tổng max
PHP:
Tong = 0
For j = 1 To Soo
    Tong = Tong + DaySo(j)
Next j
Ki = 1
   
For i = 2 To Er - Soo + 1
    Tong1 = 0
    For j = i To i + Soo - 1
        Tong1 = Tong1 + DaySo(j)
    Next j
    
    If Tong < Tong1 Then
       Tong = Tong1
       Ki = i
    End If
Next i
và đoạn hiển thị KQ

PHP:
Range("B1").Value = "Tong can tim la " & Tong
i = 0
For j = Ki To Ki + Soo - 1
    i = i + 1
    Range("C" & i).Value = DaySo(j)
Next j
---------------------------
Nội dung đầy đủ, để các bạn có thể ứng dụng lun:

PHP:
Sub TongMax()
Dim Tong As Integer
Dim Tong1 As Integer
Dim Ki As Integer
Dim Soo As Integer
Dim Er As Integer
Dim i As Integer, j As Integer

Dim DaySo() As Double

Soo = Range("D1").Value
Er = Range("A1000").End(xlUp).Row

Columns("C:C").ClearContents
Range("B1").ClearContents

If Soo > Er Then
    MsgBox "Nhap so nho hon " & Er
    Range("D1").ClearContents
    Exit Sub
End If

ReDim DaySo(Er)
For i = 1 To Er
   DaySo(i) = Range("A" & i).Value
Next i

Tong = 0
For j = 1 To Soo
    Tong = Tong + DaySo(j)
Next j
Ki = 1
   
For i = 2 To Er - Soo + 1
    Tong1 = 0
    For j = i To i + Soo - 1
        Tong1 = Tong1 + DaySo(j)
    Next j
    
    If Tong < Tong1 Then
       Tong = Tong1
       Ki = i
    End If
Next i

Range("B1").Value = "Tong can tim la " & Tong
i = 0
For j = Ki To Ki + Soo - 1
    i = i + 1
    Range("C" & i).Value = DaySo(j)
Next j

End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Uh... đúng... tôi sơ ý cái vụ số âm... cảm ơn Tigertiger đã nhắc nhở... (ra dc tới đó là lùng bùng lỗ tai lắm rồi.. hi.. hi...)
Mong bạn góp thêm nhiều bài tập nữa cho tôi và các bạn mới học có điều kiện thực tập..
Mến
ANH TUẤN
 
Upvote 0
anhtuan1066 đã viết:
Uh... đúng... tôi sơ ý cái vụ số âm... cảm ơn Tigertiger đã nhắc nhở... (ra dc tới đó là lùng bùng lỗ tai lắm rồi.. hi.. hi...)
Mong bạn góp thêm nhiều bài tập nữa cho tôi và các bạn mới học có điều kiện thực tập..
Mến
ANH TUẤN
oh, viết vậy để atuan... chú ý : nếu chất bài này ứng dụng vào chọn số liệu mưa 3 ngày max, 5 ngày max, ... thì chắc chắn số liệu mưa này là >=0 tất.

Nhưng khi viết Chương trình thì chúng ta phải chú ý tất cả các trường hợp, hi hi hi
 
Lần chỉnh sửa cuối:
Upvote 0
Giải bài tập của bạn Tiger (tạm gọi là BT2 mức đô 2)

Giải bài tập của bạn Tiger tớ gợi ý là dùng biến kiểu mảng.
Nói thêm 1 chút:
Biến kiểu mảng là biến có dạng: Bien(1 to n) với n là 1 hằng cụ thể. Biến này có n giá trị lần lượt Bien(1) , Bien(2) ... Bien(n).
Cao cấp hơn có biến mảng 2 chiều Bien(1 to n, 1 to m) với m, n là các hằng cụ thể. Biến 2 chiều thích hợp để xử lý bảng tính m dòng và n cột. Tương tự là biến nhiều chiều sử dụng trong lĩnh vực khác mà theo trính độ của mình là hơi trừu tượng.
Ở bài tập của Ban Tiger, mình đưa luôn trường hợp tổng quát của dãy số vào (chưa có trường hợp tổng quát của số cell liên tiếp cần tính tổng):
- Giá trị cần tính nằm ở cột A bắt đầu là A2 xuống ước chừng dưới 100 dòng. nếu nhiều thì ước nhiều hơn.
- số cell liên tiếp để tính tổng là 3.
Mã:
[COLOR=black]Sub Tongmax()[/COLOR]
[COLOR=black]' Khai báo biến[/COLOR]
[COLOR=black]Dim Sok(1 to 100) , Tam , Sum3 as Single[/COLOR]
[COLOR=black]Dim Rcell(1 to 3) , nRow as Integer[/COLOR]
[COLOR=black]Dim Add(1 to 3) as String[/COLOR]
[COLOR=black]' Gán giá trị cho biến[/COLOR]
[COLOR=black]Sum3 = 0[/COLOR]
[COLOR=black]nRow=Range("A2").End(xldown).Row()[/COLOR]
[COLOR=black]For k = 1 to nRow[/COLOR]
[COLOR=black]Sok(k) = Range("A1").Offset(k,0).Value[/COLOR]
[COLOR=black]Next k[/COLOR]
[COLOR=black]' Phần code[/COLOR]
[COLOR=black]For 1 = 1 to nRow - 2 ' Giảm được 2 vòng lặp, nếu là m thì giảm m-1 vòng lặp[/COLOR]
[COLOR=black]Tam = Sok(i) + Sok(i+1) + Sok(i+2)[/COLOR]
[COLOR=black]If Tam > Sum3 Then[/COLOR]
[COLOR=black]Sum3 = Tam[/COLOR]
[COLOR=black]Rcell(1) = i + 1[/COLOR]
[COLOR=black]Rcell(2) = i + 2[/COLOR]
[COLOR=black]Rcell(3) = i + 3[/COLOR]
[COLOR=black]' Hoặc nếu số cell tình tổng là m lấy từ 1 cell trên bảng tính ([/COLOR][COLOR=red]m = Range("B1").Value[/COLOR][COLOR=black]):[/COLOR]
[COLOR=black]' For j = 1 to m[/COLOR]
[COLOR=black]' Rcell(j) = i + j[/COLOR]
[COLOR=black]' Next j[/COLOR]
[COLOR=black]End If[/COLOR]
[COLOR=black]Next i[/COLOR]
 
[COLOR=black]' Địa chỉ các cell đã tìm được:[/COLOR]
[COLOR=black]Add(1) = Range("A" & Rcell(1)).Address[/COLOR]
[COLOR=black]Add(2) = Range("A" & Rcell(2)).Address[/COLOR]
[COLOR=black]Add(3) = Range("A" & Rcell(3)).Address[/COLOR]
[COLOR=black]' Hoặc nếu số cell tình tổng là m lấy từ 1 cell trên bảng tính ([/COLOR][COLOR=red]m = Range("B1").Value[/COLOR][COLOR=black]):[/COLOR]
[COLOR=black]' For iX = 1 to m[/COLOR]
[COLOR=black]' Add(iX) = Range("A" & Rcell(iX)).Address[/COLOR]
[COLOR=black]' Next iX[/COLOR]
 
[COLOR=black]' Đánh dấu chọn các cell vừa tìm được (hoặc tô màu tùy bạn)[/COLOR]
[COLOR=black]Range(Add(1) &":" & Add(m)).Select[/COLOR]
[COLOR=black]Range("B2").Value = "Tong lon nhat là " & Sum3 [/COLOR]
 
[COLOR=black]End Sub[/COLOR]
Tớ đã dự trù có thể mở rộng ra số cell cần tính tổng là cho trước ở 1 cell B1, các dòng lệnh tổng quát là các dòng có dấu nháy; nhưng lại bí ở dòng tính tổng Sum3 = Sok(1) + Sok(2) +... + Sok(m). Nhờ các bạn góp ý cho theo hướng này.
 
Lần chỉnh sửa cuối:
Upvote 0
Oh! Post bài lên rồi mới đọc kỹ lại, Bài #85 của Tiger không những giống mà còn hay hơn bài mình, nhất là phần ReDim. Chí mình bé may gặp chí lớn rồi.
Nhân tiện nhờ Tiger chỉ hộ, mình khai báo biến mảng Dim Sok(1 to nRow) thì không được, nhưng bạn khai báo Dim Sok(nRow) lại được là lý do gì?
 
Lần chỉnh sửa cuối:
Upvote 0
ptm0412 đã viết:
...chí mình bé gặp chí lớn ...
........
Nhân tiện nhờ Tiger chỉ hộ, mình khai báo biến mảng Dim Sok(1 to nRow) thì không được, nhưng bạn khai báo Dim Sok(nRow) lại được là lý do gì?

* oh ptm0412 - khiêm tốn quá, tigertiger cũng đang học hỏi thôi,

* Cách khai báo như của ptm0412 là khai báo mảng tĩnh (tức là cố định số phần tử)

Cách khai báo như của tigertiger là khai báo mảng động (tức là số phần tử mảng chỉ được xác định khi dùng lệnh ReDim)

PHP:
Dim <ten mang>() As <kiểu dữ liệu>   ' chưa xác định số p.tử

         'sau đoạn lệnh chúng ta xác định số phần tử chính xác rồi 
         'thì mới dùng lệnh ReDim
         
         ReDim <ten mang>( <biến lưu số phân tử> )
Sơ sơ như vậy chắc bạn hiểu,
 
Lần chỉnh sửa cuối:
Upvote 0
Giải bài tập đếm từ trong thư (BT1 mức độ 2) bằng biến tạm

Mặc dù bài Đếm từ Darling trong bức thư tình các bạn khác đã giải quyết xong nhưng vì lỡ ra bài trong mức độ 2 là dùng biến tạm ,nay tớ gởi lên bài giải theo hướng này để các bạn mới bắt đầu học theo kịp.

Mã:
Sub Demtu()
Mystr = LCase(Trim(Range("A1").Value))
Word = LCase(Trim(Range("A2").Value))
Kq = 0
L1 = Len(Mystr)
For i = 1 To L1
Trich = Mid(Mystr, i, 1)
Tam = Tam & Trich
If Trich = " " Then
If Trim(Tam) = Word Then
Kq = Kq + 1
Tam = ""
Else
Tam = ""
End If
End If

Next i
Range("B1").Value = "So tu " & Word & " la " & Kq
End Sub

Lưu ý: Các bạn thấy biến tạm được sử dụng lại nhiều lần, trước khi dùng lại phải giải phóng nó: Tam = "".
 
Upvote 0
Bài tập FOR tiếp theo

bài B3 (mức độ 2):

Cho 1 dãy số nguyên (được chứa vào các ô của 1 cột - chẳng hạn 10 số từ A1,A2,...,A10).
Tìm phần tử max của dãy số


Vd dãy số 18 15 5 88 70 16 45 26 25 30
kQ: max = 88 tại vị trí 4 trong dãy

* Tương tự bài toán tìm min của dãy



và bài sau là tìm max thỏa mãn đ/k,

bài B4 (mức (mức độ 2):

Cho 1 dãy số nguyên (được chứa vào các ô của 1 cột - chẳng hạn 10 số từ A1,A2,...,A10).
Tìm phần tử max (và cả vị trí của nó) trong các phần tử thỏa mãn điều kiện nào đó - chẳng hạn điều kiện chia hết cho 3 và chia hết cho 5


Vd dãy số 18 15 5 88 70 16 45 26 25 30
kQ: max = 45 tại vị trí 7 trong dãy


* Tương tự bài toán tìm min trong các phần tử thỏa mãn đ/k....



Đây là các ví dụ cơ bản ứng dụng FOR và IF hy vọng đáp ứng cho những người mới tìm hiểu FOR và IF - dĩ nhiên là chúng ta có thể dễ dàng tìm max, min bằng hàm công thức của Excel - nhưng đôi khi trong 1 công đoạn nào đó của Chương trinhg VBA chúng ta phải xác định điều này. và trên hết đây là mục đích hiểu ứng dụng FOR và IF hơn,


**
MỞ RỘNG

+ Nếu có đ/k chúng ta có thể Mở Rộng hơn (B3m, B4m): các bài này cho MA TRẬN - bảng 2 chiều -có m hàng n cột (max/min và max/min trong các phần tử thỏa mãn đ/k) - khi đó sd 2 vòng FOR lồng nhau rất hấp dẫn.

+ Bên cạnh đó ta cũng thể tự nghĩ ra các đ/k hay hơn (mong các bạn sáng tạo)



mong góp ý kiến và hoàn thiện, Thanks a lot!

 
Lần chỉnh sửa cuối:
Upvote 0
Tạm thời giãi bài 4 như sau:
PHP:
Sub Solonnhat()
Dim Er As Integer
Dim Max As Integer
Dim chia1 As Integer
Dim chia2 As Integer
Dim Sochia As Integer
Er = Range("A1000").End(xlUp).Row
Max = Range("A1").Value
chia1 = Range("B2").Value
chia2 = Range("B3").Value
For i = 1 To Er
Sochia = Cells(i, 1).Value
If Sochia Mod chia1 = 0 And Sochia Mod chia2 = 0 And Max <= Cells(i, 1).Value Then
Max = Cells(i, 1).Value
End If
Next i
If Max Mod chia1 <> 0 Or Max Mod chia2 <> 0 Then
MsgBox "Khong co so nao thoa dieu kien"
Range("B1").ClearContents
Exit Sub
End If
Range("B1").Value = Max
End Sub
Hic... hic... Giờ lại thêm cái món ReDim gì gì đó.. nhức đầu quá... Học như chạy giặc...
 
Upvote 0
atuan... làm nhanh nhỉ, mới chỉ góp ý nhỏ sau:

PHP:
 Max = Range("A1").Value
lệnh này ko ổn aTuan... ah, vì giả sử phần tử đầu tiên không thỏa thỏa mãn đ/k đề bài và có giá trị rất lớn - lớn hơn tất các phần tử còn lại -> khi đó đ/k sau k bao giờ xảy ra vì Max <= Cells(i, 1).Value luôn là false
PHP:
 If Sochia Mod chia1 = 0 And Sochia Mod chia2 = 0 And Max <= Cells(i, 1).Value Then
-> KQ sẽ sai (KQ là "Khong co so nao thoa dieu kien")

Để dễ hỉu bài B4 chúng ta xem vd công việc cụ thể tương tự như sau: chẳng hạn 1 trường ĐH dán điểm thi ĐH (điểm thi đầu vào) tại bảng tin (có đông thí sinh hơn 1000 ) , bây giờ cần tìm thí sinh có quê ở Quảng Ngãi mà điểm cao nhất (max - cao nhất trong những thí sinh cùng quê Quảng Ngãi) -> vậy ta phải làm thế nào?

ta sẽ
+ lần lượt dò tìm từ Thí sinh (TS) đầu tiên trong danh sách nếu gặp TS ko phải quê Quảng Ngãi (QN) thì bỏ qua, đến khi gặp TS có quê là Quảng Ngãi (QN) thì ghi nhận điểm của TS này - giả thiết là max nhất

+ và tiếp tục rà tìm TS tiếp theo nếu gặp TS ko phải quê Quảng Ngãi (QN) thì bỏ qua, đến khi gặp TS có quê là Quảng Ngãi (QN) thì so sánh max (ghi nhận trên) và điểm TS này, nếu max nhỏ hơn thì ghi nhận max mới là điểm của TS này trái lại bỏ qua. cứ như vậy đến kết thúc bảng thì chúng ta sẽ biết điểm max bằng bao nhiêu, và trong quá trình ghi nhận max như vậy chúng ta nhớ thêm số báo danh (SBD) nữa -> kết q chúng ta còn thêm là TS số SBD là bao nhiêu quê ở QN có điểm cao nhất là ....


Từ bài toán trên thấy tương tự bài B4 ở chỗ là tìm max (điểm cao nhất) của TS thỏa mãn đ/k quê QN,
áp dụng vào bài B4: chúng ta thấy chúng ta phải xét sao cho:

+ tìm được phần tử đầu tiên thuộc dãy (kể từ đầu dãy) thỏa mãn <đ/k> thì gán max = giá trị phần tử này> và đồng thời ghi nhận vị trí của phần tử này iV=i (iV là i Vị trí của phần tử max)
+ tiếp theo dò tìm các phần tử tiếp nếu gặp phần tử nào thỏa mãn đ/k thì lấy max so sánh với giá trị đó nếu max nhỏ hơn thì gán max = <giá trị phần tử này> và ghi nhận iV=i; trái lại bỏ qua, cứ như vậy đến hết dãy
->kQ cần tìm max

vấn đề đặt ra cần lưu ý là dãy có thể ko có phần tử nào thỏa mãn <d/k> và làm sao để nhận dạng phần tử đầu tiên thỏa mãn đ/k: giải pháp là chúng ta thêm 1 biến điếm d chẳng hạn để điếm số phần tử thỏa mãn đ/k, như thế: sẽ kiểm tra được khi d=1 là tương ứng phần tử đầu tiên. còn cuối cùng xuất kQ thì nếu d-0 -> ko có p tử t/m đ/k,....

hy vọng giải thích qua như vậy giúp mọi ng hiểu hơn - các bạn có cách giải thích nào hay hơn - đóng góp nhé



 
Lần chỉnh sửa cuối:
Upvote 0
Cảm ơn, tôi hiểu rồi... Nhưng nếu tôi gán giá trị Max đầu tiên chính là số nhỏ nhất trong dảy thì sao? Có vấn đề gì ko?
Mã:
Max = WorksheetFunction.Min(Range("A1:A" & Er))
ANH TUẤN

Nhân đây tôi gữi lên 2 bài tập tìm bội số chung nhỏ nhất và ước số chung lớn nhất... Các bạn xem thử có chổ nào ko ổn nha:
BSCNN:
PHP:
Sub BSCNN()
So1 = Range("C1").Value
So2 = Range("C2").Value
TICH = So1 * So2
If So1 = 0 Or So2 = 0 Then
   MsgBox "Luu y nhap so khac 0"
   Range("C1:C2").ClearContents
   Exit Sub
End If
For i = 1 To TICH
    If i Mod So1 = 0 And i Mod So2 = 0 Then
       Range("C3").Value = i
       Exit Sub
    End If
Next i
End Sub
USCLN:
PHP:
Sub USCLN()
So1 = Range("C1").Value
So2 = Range("C2").Value
If So1 = 0 Or So2 = 0 Then
   So = 1
ElseIf So1 <= So2 Then
       So = So1
Else: So = So2
End If
For i = 1 To So
    If So1 Mod i = 0 And So2 Mod i = 0 Then
       Range("C3").Value = i
    End If
Next i
End Sub
ANH TUẤN
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
ptm0412 đã viết:
Giải bài tập của bạn Tiger tớ gợi ý là dùng biến kiểu mảng.
Nói thêm 1 chút:
Biến kiểu mảng là biến có dạng: Bien(1 to n) với n là 1 hằng cụ thể. Biến này có n giá trị lần lượt Bien(1) , Bien(2) ... Bien(n).
Cao cấp hơn có biến mảng 2 chiều Bien(1 to n, 1 to m) với m, n là các hằng cụ thể. Biến 2 chiều thích hợp để xử lý bảng tính m dòng và n cột. Tương tự là biến nhiều chiều sử dụng trong lĩnh vực khác mà theo trính độ của mình là hơi trừu tượng.
Ở bài tập của Ban Tiger, mình đưa luôn trường hợp tổng quát của dãy số vào (chưa có trường hợp tổng quát của số cell liên tiếp cần tính tổng):
- Giá trị cần tính nằm ở cột A bắt đầu là A2 xuống ước chừng dưới 100 dòng. nếu nhiều thì ước nhiều hơn.
- số cell liên tiếp để tính tổng là 3.
Mã:
[COLOR=black]Sub Tongmax()[/COLOR]
[COLOR=black]' Khai báo biến[/COLOR]
[COLOR=black]Dim Sok(1 to 100) , Tam , Sum3 as Single[/COLOR]
[COLOR=black]Dim Rcell(1 to 3) , nRow as Integer[/COLOR]
[COLOR=black]Dim Add(1 to 3) as String[/COLOR]
[COLOR=black]' Gán giá trị cho biến[/COLOR]
[COLOR=black]Sum3 = 0[/COLOR]
[COLOR=black]nRow=Range("A2").End(xldown).Row()[/COLOR]
[COLOR=black]For k = 1 to nRow[/COLOR]
[COLOR=black]Sok(k) = Range("A1").Offset(k,0).Value[/COLOR]
[COLOR=black]Next k[/COLOR]
[COLOR=black]' Phần code[/COLOR]
[COLOR=black]For 1 = 1 to nRow - 2 ' Giảm được 2 vòng lặp, nếu là m thì giảm m-1 vòng lặp[/COLOR]
[COLOR=black]Tam = Sok(i) + Sok(i+1) + Sok(i+2)[/COLOR]
[COLOR=black]If Tam > Sum3 Then[/COLOR]
[COLOR=black]Sum3 = Tam[/COLOR]
[COLOR=black]Rcell(1) = i + 1[/COLOR]
[COLOR=black]Rcell(2) = i + 2[/COLOR]
[COLOR=black]Rcell(3) = i + 3[/COLOR]
[COLOR=black]' Hoặc nếu số cell tình tổng là m lấy từ 1 cell trên bảng tính ([/COLOR][COLOR=red]m = Range("B1").Value[/COLOR][COLOR=black]):[/COLOR]
[COLOR=black]' For j = 1 to m[/COLOR]
[COLOR=black]' Rcell(j) = i + j[/COLOR]
[COLOR=black]' Next j[/COLOR]
[COLOR=black]End If[/COLOR]
[COLOR=black]Next i[/COLOR]
 
[COLOR=black]' Địa chỉ các cell đã tìm được:[/COLOR]
[COLOR=black]Add(1) = Range("A" & Rcell(1)).Address[/COLOR]
[COLOR=black]Add(2) = Range("A" & Rcell(2)).Address[/COLOR]
[COLOR=black]Add(3) = Range("A" & Rcell(3)).Address[/COLOR]
[COLOR=black]' Hoặc nếu số cell tình tổng là m lấy từ 1 cell trên bảng tính ([/COLOR][COLOR=red]m = Range("B1").Value[/COLOR][COLOR=black]):[/COLOR]
[COLOR=black]' For iX = 1 to m[/COLOR]
[COLOR=black]' Add(iX) = Range("A" & Rcell(iX)).Address[/COLOR]
[COLOR=black]' Next iX[/COLOR]
 
[COLOR=black]' Đánh dấu chọn các cell vừa tìm được (hoặc tô màu tùy bạn)[/COLOR]
[COLOR=black]Range(Add(1) &":" & Add(m)).Select[/COLOR]
[COLOR=black]Range("B2").Value = "Tong lon nhat là " & Sum3 [/COLOR]
 
[COLOR=black]End Sub[/COLOR]
Tớ đã dự trù có thể mở rộng ra số cell cần tính tổng là cho trước ở 1 cell B1, các dòng lệnh tổng quát là các dòng có dấu nháy; nhưng lại bí ở dòng tính tổng Sum3 = Sok(1) + Sok(2) +... + Sok(m). Nhờ các bạn góp ý cho theo hướng này.

Dài thế nhỉ, em xin phép đóng góp 1 UF nhé :

PHP:
Function TongMax(Mang As Range, SoPhanTu As Byte) As String
    On Error Resume Next
    Application.Volatile (False)
    Dim Tong As Long, i As Long, i1 As Long, Temp As Long, ViTri As Long
    If Mang.Rows.Count < SoPhanTu Or Mang.Columns.Count > 1 Then Exit Function
    For i = 1 To Mang.Rows.Count - SoPhanTu + 1
        If i = 1 Then
            For i1 = i To i + SoPhanTu - 1
                Tong = Tong + Mang(i1)
            Next
            ViTri = 1
        Else
            Temp = 0
            For i1 = i To i + SoPhanTu - 1
                Temp = Temp + Mang(i1)
            Next
            If Tong < Temp Then Tong = Temp: ViTri = i
        End If
    Next
    TongMax = "Max la: " & Format(Tong, "#,##0") & " bat dau tu vi tri thu " & Format(ViTri, "#,##0")
    Set Mang = Nothing
End Function
Thân!
 

File đính kèm

  • TongMax.xls
    81.5 KB · Đọc: 48
Upvote 0
anhtuan1066 đã viết:
Cảm ơn, tôi hiểu rồi... Nhưng nếu tôi gán giá trị Max đầu tiên chính là số nhỏ nhất trong dảy thì sao? Có vấn đề gì ko?
Mã:
Max = WorksheetFunction.Min(Range("A1:A" & Er))
ANH TUẤN
ok thế thì k vấn đề gì, nhưng không nên làm thế, ta đang đi xd bài toán tìm max, giờ ta lại dùng hàm excel tìm min (hic)- quan trọng hơn làm như vậy ta lại làm bài toán tìm min (dĩ nhiên sẽ mất thời gian thêm - dù điều này excel làm và cùng với bài toán nhỏ nên chúng ta k thấy).
 
Upvote 0
Web KT
Back
Top Bottom