VBA Đối số là mảng có thể thay đổi kích thước ParamArray

Hôm nay tôi sẽ giới thiệu cách khai báo đối số là mảng, sử dụng ParamArray .
Chúng ta khai báo như sau:
Mã:
Sub TenThuTuc(ParamArray DoiSo() As Variant)

End Sub
Khi sử dụng ParamArray thì bạn phải khai báo ở cuối.
Mã:
Sub TenThuTuc(DoiSo1 As Integer, ParamArray DoiSo2() As Variant)

End Sub

' Không khai báo như thế này được nhé:
Sub TenThuTuc(ParamArray DoiSo1() As Variant, DoiSo2 As Integer)

End Sub
Bạn không thể sử dụng ByVal, ByRef, Optional cho ParamArray.

Dưới đây là các ví dụ lỗi:
Mã:
' Khong khai bao nhu the nay duoc nhe
Sub TenThuTuc(ParamArray ByVal DoiSo1() As Variant)

End Sub

' Khong khai bao nhu the nay duoc nhe
Sub TenThuTuc(Optional ParamArray DoiSo1() As Variant)

End Sub

' Khong khai bao nhu the nay duoc nhe
Sub TenThuTuc(Optional DoiSo1 As Integer = 1, ParamArray DoiSo2() As Variant)

End Sub
Hãy xem các ví du dưới đây:
Mã:
Sub ThucThi()
    Call ViDu(1, 2, 3)         ' 1,2,3
    Call ViDu("Tips", "found") ' Tips,found
    Call ViDu("Tips", 2)       ' Tips,2
End Sub

' Thu tuc con
Sub ViDu(ParamArray DoiSo() As Variant)
    Debug.Print(Join(DoiSo, ",")) ' Xuất mảng được phân tách bằng dấu phẩy
End Sub
Đối số ở trước ParamArray sẽ được ưu tiên truyền giá trị trước. Hãy xem ví dụ dưới đây:
Mã:
Sub ThucThi()
    Call Vidu(1, 2, 3)         ' 2,3
    Call Vidu("Tips", "found") ' found
End Sub

' Thu tuc con
Sub Vidu(DoiSo1 As String, ParamArray DoiSo2() As Variant)
    Debug.Print(Join(DoiSo2, ",")) ' Xuất mảng được phân tách bằng dấu phẩy
End Sub
Nguồn:
 

Euler

Administrator
Thành viên BQT
Trên diễn đàn vừa qua đã có những bài viết xử lý bằng ParamArray một cách mẫu mực.
Tôi xin được viết tóm tắt lại ở đây.
Nếu đầu vào một hàm là một vùng Range không xác định trước, kích thước thay đổi tùy ý.
Ví dụ :
Mã:
Function vidu("A2:B10","C2","D10")
hoặc:
Mã:
Function vidu("A2:B10","C2","D10","E15")
Khi đó chúng ta nghĩ tới đối số khai báo bằng ParamArray:


Mã:
Function noiso(ParamArray arr() As Variant) As String
    Dim r
    Dim r1  As Range
    
    Dim s   As String
    On Error GoTo thoat
    For Each r In arr
        If TypeOf r Is Range Then
            For Each r1 In r
                s = s & "," & r1.Value
            Next r1
            
        End If
        
    Next r
    s = Replace(s, ",,", ",", , , vbTextCompare)
    noiso = main(s)
thoat:

End Function
Tại sao lại có hai vòng lặp For Each ở trên là vì:
Nếu chỉ là C2 thì đây là một cells. Nhưng nếu là:
Mã:
A2:B10
thì chúng ta phải duyệt từng cells.
Bạn cần đăng nhập để thấy đính kèm

Như vậy For each 1 để tách ra từng Range trong một Range lớn.
For each 2 để tách ra từng cells ứng với mỗi Range.

Xử lý ở trên tôi nói là mẫu mực, vì bạn có thể ứng dụng nó trong nhiều chương trình khác.
Chẳng hạn như yêu cầu .
("A1","C3","B5") kết quả là Range("A1:C5")
Bạn cần đăng nhập để thấy đính kèm

("B2","C7","F3","D5") kết quả là Range("B2:F7")
Bạn cần đăng nhập để thấy đính kèm


Mã:
"B2:C7","B2:F3","B2:D5","C3:F7" Kết quả mong muốn là B2 : F7
Bạn cần đăng nhập để thấy đính kèm


Đầu tiên, tôi cảm ơn chủ topic đã nêu ra yêu cầu vô cùng dễ hiểu, phản biện cũng rất trực quan, theo đúng phong cách THVBA.
Đối với code .
Mã:
Sub test()
    Dim r As Range
    Set r = LayRangeLonNhat("B2:C7", "B2:F3", "B2:D5", "C3:F7", "")
    Debug.Print r.Address(False, False)
End Sub
Private Function LayRangeLonNhat(ParamArray parrDiaChi()) As Range
    Dim adr As Variant, r1  As Range
  
    Dim CotLonNhat As Long: CotLonNhat = 0
    Dim CotNhoNhat As Long: CotNhoNhat = Rows.Count
    Dim DongLonNhat As Long: DongLonNhat = 0
    Dim DongNhoNhat As Long: DongNhoNhat = Columns.Count
  
    On Error GoTo tiep
  
    For Each adr In parrDiaChi
      
            For Each r1 In Range(adr)

                CotLonNhat = IIf(r1.Column > CotLonNhat, r1.Column, CotLonNhat)
                CotNhoNhat = IIf(r1.Column < CotNhoNhat, r1.Column, CotNhoNhat)
                DongLonNhat = IIf(r1.Row > DongLonNhat, r1.Row, DongLonNhat)
                DongNhoNhat = IIf(r1.Row < DongNhoNhat, r1.Row, DongNhoNhat)
tiep:
    If r1 Is Nothing Then GoTo tiep2
            Next r1
      
tiep2:
  
    Next adr
    Set LayRangeLonNhat = Range(Cells(DongNhoNhat, CotNhoNhat), Cells(DongLonNhat, CotLonNhat))
End Function
Lại một lần nữa ta thấy ParamArray đã được sử dụng khéo léo.
Thực chất cách sử dụng này vẫn giống ở cách sử dụng trước đó. Tức là sử dụng hai vòng lặp For each.
 

NhanSu

SMod
Thành viên BQT
Vòng For ở trong có thể rút gọn. Khi một range r có địa chỉ ví dụ là B2:C100, để lấy dòng cột nhỏ nhất thì chỉ cần lấy địa chỉ của ô trên trái là r.cells(1,1); để lấy dòng cột lớn nhất thì xét ô r.cells(r.rows.count,r.columns.count). Các ô trung gian thì không có dòng cột lớn nhất hay nhỏ nhất được.
 
Top