Hàm MAX và lập trình VBA (1 người xem)

Liên hệ QC

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

VetMini

Ăn cùng góc phố
Tham gia
21/12/12
Bài viết
17,782
Được thích
24,624
Ngồi buồn ngứa tay, viết thử cái hàm MAX không dùng vòng lặp (ngôn ngữ khác có vài cách, nhưng riêng VBA, tôi chưa tìm ra cách nào khác ngoài đệ quy để thay thế vòng lặp)

Mã:
Function RgMax(ByVal rg As Range) As Double
' hàm tính max của một range. Hàm này gọi hàm con để duyệt range theo đệ quy
    If rg.Count < 1 Then
        RgMax = -9E+20
    Else
        RgMax = RgMaxRecur(rg, 1, rg.Count)
    End If
End Function

Private Function RgMaxRecur(rg As Range, ByVal cur As Integer, ByVal last As Integer) As Double
' hàm duyệt một range và lấy max
' hàm này không phải là hàm giao diện cho nên nó không có chỗ xét lỗi vượt phạm vi. Hàm gọi nó phải tự xét.
Dim mx as Double
If cur >= last Then
    RgMaxRecur = rg.Cells(last)
Else
    mx = RgMaxRecur(rg, cur + 1, last)
    RgMaxRecur = IIf(mx > rg.Cells(cur), mx, rg.Cells(cur))
End If
End Function
 
Thử góp thêm cách này xem
Mã:
Function mx(r As Range)
 i = 1: mx = r(i)
0:     If i > r.Count Then Exit Function
        If r(i) > mx Then mx = r(i)
        i = i + 1
         GoTo 0
End Function
 
Upvote 0
Cả 2 hàm MAX ở bài 1 và 2, chẳng cái nào hoạt động giống với hàm MAX của anh Bill cả
 
Upvote 0
Tôi chỉ dùng code để diễn tả thuật toán.
Hàm MAX của Excel được có giao diện rộng hơn để nhận nhiều kiểu tham số. Để thực hiện thì phải code thêm cái hàm giao diện.
 
Upvote 0
Để đạt đến gần với khả năng chính thức của hàm Application.MAX, cái giao diện phải được viết theo kiểu nhận mảng tham số (*)

Nếu chỉ làm đến một tầng (các phần tử trong mảng tham số phải là số, mảng, hoặc range; nhưng không được qua tầng kế tiếp, tức là lại tiếp tục mảng tham số) thì trên net đã có người làm. Các bạn có thể tham khảo qua link này để học hỏi thêm về kỹ thuật mảng tham số:

http://www.tushar-mehta.com/publish_train/xl_vba_cases/1005 ParamArray.shtml

Nếu cho phép số tầng vô hạn, tức là mỗi phần tử lại có thể là một mảng tham số, thì bắt buộc phải dùng đệ quy. Mà đệ quy loại này không còn thuần tuý trực tuyến nữa, tương đối phức tạp. Đây chỉ có thể là đề tài cho học lập trình chứ nó đi khá xa khỏi ứng dụng Excel.

(*) nếu tôi không lầm thì cái hàm JoinText nổi tiếng trên DD này dùng giao diện mảng tham số. Cho nên nó cũng không hẳn là lạ lắm đối với các bạn.
 
Upvote 0
Không đệ quy, thấy cũng giống giống cái của anh Bill.
PHP:
Function UDFMax(ParamArray Args() As Variant)
Dim i As Long, Tmp As Variant, Itm, Check As Boolean
For i = LBound(Args) To UBound(Args)
    Tmp = Args(i)
    If IsArray(Tmp) Then
        For Each Itm In Tmp
            Select Case VarType(Itm)
            Case 10
                UDFMax = Itm:   Exit Function
            Case 2 To 7
                If Not Check Then
                    UDFMax = Itm:   Check = True
                Else
                    If Itm > UDFMax Then UDFMax = Itm
                End If
            End Select
        Next
    Else
        Select Case VarType(Tmp)
        Case 10
            UDFMax = Tmp:   Exit Function
        Case 2 To 7
            If Not Check Then
                UDFMax = Tmp:   Check = True
            Else
                If Tmp > UDFMax Then UDFMax = Tmp
            End If
        Case Else
            UDFMax = CVErr(xlErrValue):   Exit Function
        End Select
    End If
Next
If Not Check Then UDFMax = 0
End Function
 
Upvote 0
Không đệ quy, thấy cũng giống giống cái của anh Bill.
...

Tôi có nói rõ nếu chỉ 1 tầng thì không khó lắm
Chay cửa sổ Immediate:
? UDFMax(array(1,2,7),5) ' 1 tầng
7 -> kg đúng
? UDFMax(array(array(1,2,7),5)) ' 2 tầng
5 -> kq sai
? UDFMax(array(UDFMax(array(1,2,7)),5)) ' bắt buộc phải gọi chính nó để xử lý tầng thứ 2
7 -> kq đúng

Gọi chính nó là mở đầu của đệ quy. Nếu hàm viết theo kiểu đệ quy thì nó tự biết xử lý lấy. Và bao nhiêu tầng cũng được, hết bộ nhớ thì mới chết.
 
Upvote 0
Tôi có nói rõ nếu chỉ 1 tầng thì không khó lắm
Chay cửa sổ Immediate:
? UDFMax(array(1,2,7),5) ' 1 tầng
7 -> kg đúng
? UDFMax(array(array(1,2,7),5)) ' 2 tầng
5 -> kq sai
? UDFMax(array(UDFMax(array(1,2,7)),5)) ' bắt buộc phải gọi chính nó để xử lý tầng thứ 2
7 -> kq đúng

Gọi chính nó là mở đầu của đệ quy. Nếu hàm viết theo kiểu đệ quy thì nó tự biết xử lý lấy. Và bao nhiêu tầng cũng được, hết bộ nhớ thì mới chết.
Thì ra "Tầng" mà anh nói là mảng trong mảng. Nhưng mà cái này hàm MAX của anh Bill cũng đâu làm được. Và mảng trong mảng không biết bao nhiêu tầng thì phải dùng đệ quy rồi.
Nhiều tầng thì em sẽ làm thế này.
PHP:
Function UDFMax(ParamArray Args() As Variant)
Dim i As Long, Tmp As Variant, TmpMax As Variant
For i = LBound(Args) To UBound(Args)
    Tmp = Args(i)
    UDFMax_SP Tmp, TmpMax
    If VarType(TmpMax) = 10 Then GoTo ExitF
Next
ExitF:
UDFMax = TmpMax
End Function
PHP:
Private Sub UDFMax_SP(ByVal Tmp, ByRef TmpMax)
If VarType(TmpMax) = 10 Then Exit Sub
If IsArray(Tmp) Then
    Dim iTmp As Variant
    For Each iTmp In Tmp
        UDFMax_SP iTmp, TmpMax
    Next
Else
    Select Case VarType(Tmp)
    Case 10
        TmpMax = Tmp
    Case 2 To 7
        If VarType(TmpMax) = 0 Then
            TmpMax = Tmp
        Else
            If Tmp > TmpMax Then TmpMax = Tmp
        End If
    Case Else
        TmpMax = CVErr(xlErrValue)
    End Select
End If
End Sub
 
Upvote 0
Web KT

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

Back
Top Bottom