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,847
Được thích
36,380
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:
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:
Đọc nhanh mới phát hiện mấy điểm sau a tuấn ah

1) bài BSCNN

đoạn này
PHP:
'<....>
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
'<....>
đã tính tích rui, sao a ko đổi đ/k thành:
PHP:
If TICH=0 Then
như thế ngắn gọn và nhanh hơn,

2) còn bài USCLN thì phải đổi chiều vòng FOR sẽ hay hơn (dĩ nhiên khi đó phải thêm Exit sub) atuan ah

từ
PHP:
For i = 1 To So
    If So1 Mod i = 0 And So2 Mod i = 0 Then
       Range("C3").Value = i
    End If
Next i
thành như sau:

PHP:
 For i = so To 1 Step -1
    If So1 Mod i = 0 And So2 Mod i = 0 Then
       Range("C3").Value = i
       Exit Sub
    End If
Next i
và thêm Exit sub

Tuy vậy thuật toán Giải thuật Euclid tìm USCLN hơn quả: cụ thể

Giải thuật Euclid gốc
PHP:
USCLN(a,b) = a      nếu   a=b
USCLN(a,b) = USCLN(a-b, b)      nếu   a>b
USCLN(a,b) = USCLN(a, b-a)      nếu    a<b
hoặc tham khảo thêm nữa về giải thuật Euclid tìm USCLN hiệu quả:
Nếu a mod b = 0 thì USCLN = b trái lại thì USCLN(a,b) = USCLN(b, a mod b) tại đây

(Nhưng như thế lại sang vòng lặp không xác định rùi - không phải FOR)


và có tính chất USCLN và BSCNN

USCLN(a, b)·BSCNN(a, b) = a*b -> BSCNN(a, b)=a*b/ USCLN(a, b)

nên BSCNN lại thường tính qua UCSLN


hy vọng atuan... và các TV tham khảo thêm
 
Lần chỉnh sửa cuối:
Upvote 0
Mr Okebab đã viết:
Dài thế nhỉ, em xin phép đóng góp 1 UF nhé :
Thực ra cũng không quá dài đến thế. Sau khi học ReDim của bạn TigerTiger, lấy doạn code tính tổng mở rộng của bạn ấy thì được kết quả sau: (Giữ nguyên thuật toán và các câu lệnh)

Dim RCelli() As Integer
Dim Add() As String
Dim Sok(), Tam, Sum3 As Single
n = Range("A2").End(xlDown).Row()
m = Range("C1").Value
ReDim Sok(n), RCelli(m), Add(m)

For k = 1 To n
Sok(k) = Range("A1").Offset(k, 0).Value
Next k

For i = 1 To n - m + 1
For i2 = i To i + m - 1
Tam = Tam + Sok(i2)
Next i2
If Tam > Sum3 Then
Sum3 = Tam
For j = 1 To m
RCelli(j) = i + j
Add(j) = Range("A" & RCelli(j)).Address
Next j
End If
Tam = 0
Next i

Range(Add(1) & ":" & Add(m)).Select
Range("B1:B20").Clear
Range("B1").Value = "Tong lon nhat la " & Sum3

For ix = 1 To m
Range("B1").Offset(ix, 0).Value = Add(ix)
Next ix
End Sub


Trong đó phần chữ đỏ là code chính, 13 dòng
Phần chữ xanh dương là phần xuất kết quả trong đó có liệt kê địa chỉ các cell vừa tìm được. Nếu không cần liệt kê thì bỏ 5 dòng xanh và bỏ luôn dòng đỏ in đậm --> code chính còn 12 dòng.
Phần chữ xanh đậm là khai báo biến và gán giá trị cho biến, khi chuyển thành UDF thì giảm được một mớ nữa.
Không dài, không dài.
Tuy nhiên về vốn câu lệnh vẫn còn phải học nhiều ở các bạn.
 
Lần chỉnh sửa cuối:
Upvote 0
Giải bài tập 3, mức độ 2 phần mở rộng

Bài này tớ mở rộng cho cả Max, Min, tính cho bảng m dòng n cột:
- Áp dụng biến mảng 2 chiều
- Áp dụng biến mảng động
- Dùng biến tạm
- Dùng hàm iif() của VBA thay cho If then
- biến đổi thành Funtion
- nếu tính Max thì gán Tam = 0, tính Min thì Tam = tham số max dự đoán
- hàm có 3 tham số: Dịa chỉ cell đầu bên trái của bảng dữ liệu, min hoặc max, max dự đoán. Tham số Maxguess có thể bỏ trống nếu tính max và cần phải có nếu tính min.
Mã:
Function tim(Begcell As String, Ask As String, Optional MaxGuess As Double) As String
Dim RAdd, CAdd, Rcount, Ccount As Integer
Dim Data1() As Single
Dim Add As String
Rcount = Range(Begcell).End(xlDown).Row - Range(Begcell).Row + 1
Ccount = Range(Begcell).End(xlToRight).Column - Range(Begcell).Column + 1
Ask = LCase(Ask)
ReDim Data1(Rcount, Ccount)
Tam = IIf(Ask = "max", 0, MaxGuess)
For i = 1 To Rcount
For j = 1 To Ccount
Data1(i, j) = Range(Begcell).Offset(i - 1, j - 1).Value
Select Case Ask
Case "max"
If Tam > Data1(i, j) Then
Tam = Tam
Else
Tam = Data1(i, j)
RAdd = i - 1
CAdd = j - 1
End If
Case "min"
If Tam < Data1(i, j) Then
Tam = Tam
Else
Tam = Data1(i, j)
RAdd = i - 1
CAdd = j - 1
End If
End Select
Next j
Next i
Add = Range(Begcell).Offset(RAdd, CAdd).Address
tim = IIf(Ask = "max", "Gia tri lon nhat la: ", "Gia tri nho nhat la: ") & Tam
tim = tim & " tai cell " & Add
End Function
Nhờ các bạn góp ý, hình như dài, dài thật. Mà còn rối rắm những là -1 với +1.
Tớ đoán là do thuật toán chưa tối ưu, khi chạy thử thì lỗi, sửa tới sửa lui mới bị như vậy.
 

File đính kèm

  • Tinh MinMax.xls
    31.5 KB · Đọc: 41
Lần chỉnh sửa cuối:
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?
Sao không cho Max = zero?
Đến cuối nếu Max vẫn bằng zero thì
-Một là không tìm được.
-Hai là trong dãy có chứa số 0.
-->Đưa ra kết luận.

Hôm qua Post bài xong, kèm theo câu hỏi cho bạn Tigertiger là 12h đêm, đi ngủ. Bữa nay coi lại, Tiger soạn bài tập, post lên, sửa nội dung, trả lời tớ :`1h08!
Thế mới biết nhiệt tình của các bạn đối với topic này như thế nào.
Còn bạn Anhtuan, làm hết mọi bài tập, thảo luận, hăng say như trai trẻ tập yêu, cũng thật hết lòng vì mình và vì mọi người.
Còn những bạn khác nữa, sẵn sàng góp ý, sửa chữa, cho lời khuyên . . .
Thật là vui phải không? Mong rằng mọi người chung sức như vậy sẽ giúp được cho các bạn khác. Không biết sao, chứ nhìn topic: 101 lần trả lời, 1277 lần đọc là phấn khởi lắm.
Một lần nữa, cám ơn tất cả mọi người.
Tớ dự định mức độ 3 sẽ là nhiều vòng For lồng nhau, nhưng các bạn đã đẩy tiến độ nhanh hơn tớ tưởng và ứng dụng 2 vòng lồng nhau từ lâu!
Vui thật đấy.
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Bạn ptm0412 ơi! Tôi cám ơn sự nhiệt tình giúp đở của bạn... Nhưng mong rằng từ từ, đừng chuyển sang mức độ 3 vội... Bạn hảy nhìn đi... Lớp học 5, 6 thầy nhưng chỉ có 1 học sinh... ??? Sao ko ai vào tham gia nhỉ?
-Bài giãng quá cao cấp khó hiểu ?
-Mọi người đã biết tất cả rồi ?
Là nguyên nhân nào đây ???
Dù là nguyên nhân gì đi chăng tôi cũng mong rằng tất cả các bạn, những người mới học hảy mạnh dạn tham gia, sai thì sửa.. (cũng như tôi bước vào bài học này tôi có biết tí gì về FOR đâu)
Bạn ptm0412 có thể nói thêm 1 tí về vòng lập FOR dc ko? Gặp trường hợp thế nào thì xài nó? Còn tôi thì qua các bài học về FOR tôi rút ra kết luận rằng: Ta sẽ dùng FOR đối với những bài toán có tính kiểm tra loại trừ trong 1 mãng dử liệu đễ lấy ra 1 hoặc vài em thỏa điều kiện
(ko biết đúng ko?)
ANH TUẤN
 
Upvote 0
đoạn này có vẻ ko ổn
ptm0412 đã viết:
PHP:
If Tam > Data1(i, j) Then
Tam = Tam
Else
Tam = Data1(i, j)
RAdd = i - 1
CAdd = j - 1
End If
vì ko bao giờ tam=tam như thế nó lại nhận chính giá trị của nó (không thay đổi gì và ko có ý nghĩa gì - trong trường hợp này bạn dùng if khuyết - khi đó thì đổi lại đ/k ngược lạicụ thể là

PHP:
If Tam < Data1(i, j) Then
      Tam = Data1(i, j)
       RAdd = i - 1
       CAdd = j - 1
End If

tương tự đoạn min cũng vậy
mới xem qua -> có ý kiến vậy thôi
 
Lần chỉnh sửa cuối:
Upvote 0
ptm0412 đã viết:
Thực ra cũng không quá dài đến thế. Sau khi học ReDim của bạn TigerTiger, lấy doạn code tính tổng mở rộng của bạn ấy thì được kết quả sau: (Giữ nguyên thuật toán và các câu lệnh)


Trong đó phần chữ đỏ là code chính, 13 dòng
Phần chữ xanh dương là phần xuất kết quả trong đó có liệt kê địa chỉ các cell vừa tìm được. Nếu không cần liệt kê thì bỏ 5 dòng xanh và bỏ luôn dòng đỏ in đậm --> code chính còn 12 dòng.
Phần chữ xanh đậm là khai báo biến và gán giá trị cho biến, khi chuyển thành UDF thì giảm được một mớ nữa.
Không dài, không dài.
Tuy nhiên về vốn câu lệnh vẫn còn phải học nhiều ở các bạn.
Vâng, quả thực là không dài, tuy nhiên tớ chỉ có mấy góp ý thế này
Dù là Sub hay là Function thì ta đều phải
  1. Khai báo biến (Nếu có sử dụng)
  2. Bẫy lỗi
  3. Chạy chương trình chính (khi không có lỗi)
  4. Xuất ra kết quả
Vì vậy, dù làm thế nào cũng được, tuy nhiên phải đảm bảo các yếu tố đó.
Như vậy không thể nói : Bỏ đi phần này hay bỏ đi phần khác được.
Còn Sub trên : Chú ý hơn nữa phần bẫy lỗi. Tớ chưa thây được cái này.
Cả trong bài 101 cũng vậy, mà Function đặc biệt cần cái này

Thân!
 
Upvote 0
Mr Okebab đã viết:
Dù là Sub hay là Function thì ta đều phải
  1. Khai báo biến (Nếu có sử dụng)
  2. Bẫy lỗi
  3. Chạy chương trình chính (khi không có lỗi)
  4. Xuất ra kết quả
Vì vậy, dù làm thế nào cũng được, tuy nhiên phải đảm bảo các yếu tố đó.
Như vậy không thể nói : Bỏ đi phần này hay bỏ đi phần khác được.
Còn Sub trên : Chú ý hơn nữa phần bẫy lỗi. Tớ chưa thây được cái này.
Cả trong bài 101 cũng vậy, mà Function đặc biệt cần cái này

Thân!
Cám ơn bạn đã nhắc nhở. Thú thật đây là Function đầu tiên mình tự làm ra, học ở câu giải thích sau:
TigerTiger đã viết:
. . . 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.
và mình nghĩ rằng 1 số biến vẫn phải khai, một số biến lấy từ các tham số của hàm, giảm là giảm chỗ đó thôi.
Với lại, mình nghĩ, với hàm (function) sẽ chỉ trả vế 1 kết quả, phần liệt kê kết quả là dư, nên giảm nó là phải, Bạn Bab xem có đúng không.

Phần bẫy lỗi mình cũng biết sơ qua, nhưng chưa hề có kinh nghiệm, phải học hỏi nhiều, mong bạn nếu có thể viết cho 1 vài bài post lên, mình và mọi người có thêm cơ hội học hỏi.
Thân
 
Upvote 0
Xin dịch sang ngôn ngữ đời thường giúp đoạn mã sau

Mã:
Option Explicit[b]

Sub Tich2SoCong1ChiaSoThu3()[/b]
 Dim ij As Integer
 Dim bChuc As Byte, bDVi As Byte, bTram As Byte
 
 On Error Resume Next
 For ij = 100 To 999
    bChuc = (ij \ 10) Mod 10
    bDVi = ij Mod 10:               bTram = ij \ 100
    If (1 + bTram * bChuc) Mod bDVi = 0 Then
        Chep ij:            GoTo Het
    End If
    If (1 + bTram * bDVi) Mod bChuc = 0 Then
        Chep ij:            GoTo Het
    End If
    If (1 + bChuc * bTram) Mod bDVi = 0 Then
        Chep ij:                    GoTo Het
    End If
    If (1 + bChuc * bDVi) Mod bTram = 0 Then
            Chep ij:            GoTo Het
    End If
    If (1 + bDVi * bTram) Mod bChuc = 0 Then
            Chep ij:            GoTo Het
    End If
    If (1 + bDVi * bChuc) Mod bTram = 0 Then
            Chep ij:            GoTo Het
    End If
Het:  Next ij[b]
End Sub[/b]
PHP:
[b]
Sub Chep(iZ As Integer)
    Dim Rng As Range
    Set Rng = Range("B" & Range("B65432").End(xlUp).Row + 1)
    With Rng
        .Value = iZ
        If .Offset(-1, -1) <> "TT" Then
            .Offset(, -1) = .Offset(-1, -1) + 1
        Else
            .Offset(, -1) = 1
        End If
    End With
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
ptm0412 đã viết:
Cám ơn bạn đã nhắc nhở. Thú thật đây là Function đầu tiên mình tự làm ra, học ở câu giải thích sau:

và mình nghĩ rằng 1 số biến vẫn phải khai, một số biến lấy từ các tham số của hàm, giảm là giảm chỗ đó thôi.
Với lại, mình nghĩ, với hàm (function) sẽ chỉ trả vế 1 kết quả, phần liệt kê kết quả là dư, nên giảm nó là phải, Bạn Bab xem có đúng không.

Phần bẫy lỗi mình cũng biết sơ qua, nhưng chưa hề có kinh nghiệm, phải học hỏi nhiều, mong bạn nếu có thể viết cho 1 vài bài post lên, mình và mọi người có thêm cơ hội học hỏi.
Thân

Function có thể đưa ra một kết quả hoặc 1 nhóm kết quả (hàm mảng)
Vì vậy phần liệt kê cũng như nhau thôi.
Function cần khai báo rất nhiều tham số, trong khi đó sub đã có cell trợ giúp. vậy nên ngắn hơn là phải.

Tuy nhiên Function thường ngắn hơn bởi vì khi làm thì các tác giả đều cố gắng tối ưu các dòng code, thuật toán của mình, còn với SUB thì mọi người thường có quan niệm : nghĩ sao làm vậy, tức là mô tả lại công việc của một người không biết gì về VBA (tất nhiên có thể mô tả bằng thuật toán, bằng vòng lặp . . )

Hay là tớ thử làm Function trên thành Sub xem có dài hơn không nhé ??? Đùa vậy thôi, tự cậu làm được mà.

Thân!
 
Upvote 0
Mr Okebab đã viết:
Hay là tớ thử làm Function trên thành Sub xem có dài hơn không nhé ??? Đùa vậy thôi, tự cậu làm được mà.

Thân!
PHP:
Sub TongMax()
    '' Mang DuLieu : Tu A2 tro di _ _ _  So phan tu : C1 _ _ _ Ketqua : B1
    On Error Resume Next
    Dim Tong As Long, i As Long, i1 As Long, Temp As Long, ViTri As Long
    If Range("A65000").End(xlUp) < Range("C1").Value + 1 Or Range("C1").Value < 1 Then Exit Sub
    For i = 2 To Range("A65000").End(xlUp) - SoPhanTu + 1
        If i = 2 Then
            For i1 = i To i + Range("C1").Value - 1
                Tong = Tong + Range("A" & i).Value
            Next
            ViTri = 2
        Else
            Temp = 0
            For i1 = i To i + Range("C1").Value - 1
                Temp = Temp + Range("A" & i).Value
            Next
            If Tong < Temp Then Tong = Temp: ViTri = i
        End If
    Next
    Range("B1").Text = "Max la: " & Format(Tong, "#,##0") & " bat dau tu hang A" & Format(ViTri, "#,##0")
End Sub
Thân!
 
Upvote 0
Cám ơn bạn nhiều, mình thực không biết nhiều như bạn tưởng. Tối ưu hóa thuật toán là tùy thuộc vào khí chất thông minh hoặc tính chịu khó suy luận, cái này mình không bằng giới trẻ. Các thủ thuật tối ưu code mình còn phải học nhiều các câu lệnh và cấu trúc lệnh.

Bạn làm giúp sub() cho cái function dởm của mình về tìm giá trị min hoặc max trong mảng, cho mình học hỏi. Cái bạn vừa làm là tính tổng lớn nhất của 3 hoặc 5 cell liên tiếp.
 
Upvote 0
ptm0412 đã viết:
Cám ơn bạn nhiều, mình thực không biết nhiều như bạn tưởng. Tối ưu hóa thuật toán là tùy thuộc vào khí chất thông minh hoặc tính chịu khó suy luận, cái này mình không bằng giới trẻ. Các thủ thuật tối ưu code mình còn phải học nhiều các câu lệnh và cấu trúc lệnh.

Bạn làm giúp sub() cho cái function dởm của mình về tìm giá trị min hoặc max trong mảng, cho mình học hỏi. Cái bạn vừa làm là tính tổng lớn nhất của 3 hoặc 5 cell liên tiếp.
Hàm của em thì không giới hạn số phần tử là 3 hay 5 bác ạ, bao nhiêu cũng được mà.


Đây là hàm tính tổng max các phần tử liên tiếp trong cùng 1 cột của 1 mảng. Số phần tử được tính sẽ tùy người dùng khai báo.

PHP:
Function TongMM(Mang As Range, SoPhanTu As Byte, Optional Loai As String) As String
    On Error Resume Next
    Application.Volatile (False)
    Dim Tong As Double, Hang As Long, Cot As Byte, iC As Byte, _
        iR As Long, i1 As Long, Temp As Double
    If Mang.Rows.Count < SoPhanTu Then Exit Function
    For Cot = 1 To Mang.Columns.Count
        For Hang = 1 To Mang.Rows.Count - SoPhanTu + 1
            If Hang = 1 And Cot = 1 Then
                For i1 = Hang To Hang + SoPhanTu - 1
                    Tong = Tong + Mang(i1, Cot)
                Next
                iC = Cot: iR = Hang
            Else
                Temp = 0
                For i1 = Hang To Hang + SoPhanTu - 1
                    Temp = Temp + Mang(i1, Cot)
                Next
                If (Tong < Temp And UCase(Loai) = "MAX") Or (Tong > Temp And UCase(Loai) <> "MAX") Then
                    Tong = Temp: iC = Cot: iR = Hang
            End If: End If: Next Hang: Next Cot
    iR = iR + Mang.Row - 1: iC = iC + Mang.Column - 1
    TongMM = IIf(UCase(Loai) = "MAX", "Max", "Min") & " la :" & Format(Tong, "#,##0.0000") & _
            " bat dau tu vi tri " & Cells(iR, iC).Address
    Set Mang = Nothing
End Function
Còn Sub thì tương tự thôi bác ạ.

Còn hàn của bác : Bác xem File sẽ thấy khác nhau như thế nào :
  1. Khai báo biến chưa đủ
  2. Khi có số âm trong bảng thì sẽ bị sai
  3. Chưa có tham số cho tùy chọn số phần tử được tính (3, hay 5, hay 6), của bác mới chỉ là 1
Thân!


P/S : Xin lỗi bác, em cứ nghĩ rằng bác trẻ hơn em nên xưng hô như vậy.
Thành thật xin lỗi.
 

File đính kèm

  • TongMax_OB3.xls
    40.5 KB · Đọc: 46
Upvote 0
"Lơ canh chua" rồi...
Theo tới đây thì xem như "hết xăng"... Ko theo nỗi các đại ca... Hic...
Vòng lập FOR cơ bản còn đang tiêu hóa như thời bao cấp bị ép ăn bo bo... giờ thêm mấy chiêu mới lạ:
-REDIM ??? Hỏng biết
-ON ERROR RESUME NEXT ??? Hỏng biết
-APPLICATION.VOLATILE ??? Lại càng hỏng biết
Vân vân và vân vân... Một trời cái hỏng biết...
 
Upvote 0
Cạnh tranh với BAB cái, nha!

PHP:
Function MaxInColumn(CRng As Range, Optional PhanTu As Byte = 1) As String
 Dim lRow As Long, lCuoi As Long, iJ As Long
 Dim TTemp As Double, TTong As Double
 Dim Rng As Range, StrC As String
 
 lRow = CRng.Rows.Count
 If lRow < PhanTu Then
    MaxInColumn = "KHONG THE TIM!":         Exit Function
 ElseIf lRow = PhanTu Then
    MaxInColumn = "CAN TIM SAO?":           Exit Function
 Else
    lRow = lRow - PhanTu + 1:               TTemp = -999999999999#
    Set CRng = CRng.Resize(lRow, 1)
    For Each Rng In CRng
        With Rng
            TTong = Application.Sum(.Resize(PhanTu, 1))
            If TTong > TTemp Then
                TTemp = TTong:              StrC = .Resize(PhanTu, 1).Address
            End If
        End With
    Next Rng
 End If
 MaxInColumn = StrC
End Function
 
Lần chỉnh sửa cuối:
Upvote 0
anhtuan1066 đã viết:
"Lơ canh chua" rồi...
Theo tới đây thì xem như "hết xăng"... Ko theo nỗi các đại ca... Hic...
Vòng lập FOR cơ bản còn đang tiêu hóa như thời bao cấp bị ép ăn bo bo... giờ thêm mấy chiêu mới lạ:
-REDIM ??? Hỏng biết
-ON ERROR RESUME NEXT ??? Hỏng biết
-APPLICATION.VOLATILE ??? Lại càng hỏng biết
Vân vân và vân vân... Một trời cái hỏng biết...

Hiểu một cách "toàn diện" (bắt chước phim)
  1. REDIM : Khai báo lại mảng (Mà mảng thì sẽ có Số Cột và Hàng)
  2. On Error Resume Next : Nếu gặp lỗi thì . . cứ chạy tiếp
  3. Application.Volatile(True or False) : Khi có một sự thay đổi nào trong bảng tính thì công thức sẽ tính lại hay chỉ khi có sự thay đổi trong đến tham số khai báo thì nó mới tính lại
Trình độ VBA của bác tiến rất nhanh, cố lên bác ạ.
Thân!
 
Upvote 0
SA_DQ đã viết:
PHP:
Function MaxInColumn(CRng As Range, Optional PhanTu As Byte = 1) As String
 Dim lRow As Long, lCuoi As Long, iJ As Long
 Dim TTemp As Double, TTong As Double
 Dim Rng As Range, StrC As String
 
 lRow = CRng.Rows.Count
 If lRow < PhanTu Then
    MaxInColumn = "KHONG THE TIM!":         Exit Function
 ElseIf lRow = PhanTu Then
    MaxInColumn = "CAN TIM SAO?":           Exit Function
 Else
    lRow = lRow - PhanTu + 1:               TTemp = -999999999999#
    Set CRng = CRng.Resize(lRow, 1)
    For Each Rng In CRng
        With Rng
            TTong = Application.Sum(.Resize(PhanTu, 1))
            If TTong > TTemp Then
                TTemp = TTong:              StrC = .Resize(PhanTu, 1).Address
            End If
        End With
    Next Rng
 End If
 MaxInColumn = StrC
End Function
Học được của bác chiêu Resize (mặc dù chưa hiểu lắm)
Còn cách tính thì cũng tương tự thôi ạ.
Bác làm thêm phần tùy chọn max, min và cho nhiều cột nữa bác ạ.

Giả sử trong mảng có tổng các số (theo số phần tử được cộng) nhỏ hơn - 999.999.999.999 thì sao nhỉ (híc, chắc không có đâu)

Tuy nhiên em đã nói rồi, về giải thuật thì em còn đi sau bác xa lắm.

Thân!
 
Upvote 0
Ko biết thì bực mình... biết thêm thì càng thấy.. quá ngu...
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!
Tôi đễ ý thấy rằng rất khó khăn khi cố gắng tìm hiểu code của người khác (Của mình viết xong, lâu lâu xem lại có khi còn hỏng hiểu)... Vì thế mà nếu như nắm bắt dc thuật toán, rồi tự mình làm, sau đó so sánh với mẫu của các đại ca thì sẽ rút ra dc rất nhiều kinh nghiệm quý báu.. lại còn có thể tùy biến cao...
Chứ copy code mang về chạy thì chả khác nào có tiền ra siêu thị mua đồ về xài... Với bản thân tôi thì tôi chẳng khoái vụ này lắm... Tôi vẫn thích tự mình làm ra (ngon dở cũng dc).. xong thì so sánh cái của mình với của người khác.. như thế mới nghiệm ra dc code của các bạn nó "xịn" ở điểm nào chứ... he.. he... Mà muốn dc như thế thì phải hiểu thuật toán của các đại ca trước đã.. đúng ko?
ANH TUẤN
 
Upvote 0
Mr Okebab đã viết:
Hàm của em thì không giới hạn số phần tử là 3 hay 5 bác ạ, bao nhiêu cũng được mà.
Ý mình là Sub Tongmax() của bạn nhằm giải bài tập số 2 mức độ 2 của TigerTiger (tính tổng lớn nhất của 3 số liên tiếp lớn nhất, mở rộng cho 5, 7 hoặc số bất kỳ). Sub của bạn lấy số này từ cell C1 vào biến sophantu thì mình thấy rôi.

Còn hàm của bác : Bác xem File sẽ thấy khác nhau như thế nào :
  1. Khai báo biến chưa đủ
  2. Khi có số âm trong bảng thì sẽ bị sai
  3. Chưa có tham số cho tùy chọn số phần tử được tính (3, hay 5, hay 6), của bác mới chỉ là 1
Bạn xem lại, cái hàm dởm mà mình khoe là giải bài tập số 3:
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
Mình cho min, max chung vào 1 hàm, mở rộng tìm kiếm trong 1 mảng 2 chiều, tìm ra min, max, xác định vị trí, đúng yêu cầu đấy chứ. Số âm cũng tính min max (1 giá trị) đâu có vấn đề.
Còn bài số 2, mình cũng cho tổng max của n cell liên tiếp mà. Cái bài mà mình đưa lên 3 màu xanh đỏ tím vàng ấy. Bài ấy đúng là chưa tính tới số âm.
Và cả 2 bài đều chưa khai báo biến đầy đủ.


P/S : Xin lỗi bác, em cứ nghĩ rằng bác trẻ hơn em nên xưng hô như vậy.
Thành thật xin lỗi.
Hì hì, không sao, không sao. À mà tớ giấu tuổi kỹ lắm, sao bạn biết vậy?
 
Lần chỉnh sửa cuối:
Upvote 0
ptm0412 đã viết:
[/list]Bạn xem lại, cái hàm dởm mà mình khoe là giải bài tập số 3:

Mình cho min, max chung vào 1 hàm, mở rộng tìm kiếm trong 1 mảng 2 chiều, tìm ra min, max, xác định vị trí, đúng yêu cầu đấy chứ. Số âm cũng tính min max (1 giá trị) đâu có vấn đề.
Có phải hàm ở bài 101 không bác ???

Bạn xem lại, cái hàm dởm mà mình khoe là giải bài tập số 3:

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

Cái này thì theo em có 3 cách :
  1. Dùng For . . Next
  2. Dùng hàn Max, Min của excel kết hợp với Match
  3. Copy ra vùng tạm, dùng chức năng Sort rồi nhận diện Min, Max
Hì hì, không sao, không sao. À mà tớ giấu tuổi kỹ lắm, sao bạn biết vậy?
ptm0412 đã viết:
Tối ưu hóa thuật toán là tùy thuộc vào khí chất thông minh hoặc tính chịu khó suy luận, cái này mình không bằng giới trẻ.
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)

Thân!
 
Upvote 0
Web KT
Back
Top Bottom