Nhờ các thày giúp cho vài ví dụ về truyền tham số cho thủ tục Sub (hoặc hàm Function)

Liên hệ QC

Dauthivan

Thành viên tiêu biểu
Tham gia
15/8/08
Bài viết
565
Được thích
327
Em đang nghiên cứu về truyền tham số bằng giá trị (byVal tức Byvalue), em có tìm đọc trên diễn đàn thì hầu hết nói rất nhanh vấn đề này, chính vì vậy em nhờ mọi người giúp em:

- Tại sao lại phải cần thiết truyền tham số.

- Giúp em một vài ví dụ để em hiểu về "cách truyền" của nó

Xin đa tạ các thày
 
Em hiểu thế này thì có đúng không ah: nhờ Sub có cái thành phần Giatri(i, j, k) mà Funtion nó hiểu thứ tự gán như sau: a=i, b=j, c=k nghĩa là a, b,c là biến tổng quát, còn i,j,k là cụ thể hóa trong từng trường hợp phải không ah?
Bạn hiểu đúng rồi đó.
Trong hàm Giatri ở trên thì a, b, c được gọi là tham số hình thức, và các lệnh trong hàm Giatri sẽ cho biết hàm Giatri này được tính bởi công thức nào thông qua a, b, c. Còn khi sử dụng hàm này, ta phải thay các tham số hình thức này bởi các giá trị thực sự, chính là các số i, j, k được xác định bằng Inputbox trong sub Tinhs, các số i, j, k này được gọi là tham số thực sự. Và khi gọi hàm này trong chương trình, VBA sẽ thay thế các tham số hình thức bởi các tham số thực sự và dựa vào quy tắc tính toán trong dãy lệnh để cho ra một kết quả cụ thể.
Thực ra thì để tìm hiểu về vấn đề này, bạn cũng có thể tham khảo trong SGK Tin học 11 (nghĩa là học sinh phổ thông cũng đã được trang bị kiến thức này rồi).
 
Upvote 0
Đây là nhiệm vụ cụ thể để bạn dễ hình dung thêm:

Có 1 bạn trên diễn đàn nhờ bạn tạo mã duy nhất cho cở 750 nhân viên trong cơ quan với qui tắc sau:

Mã gồm 2 ký tự & nối tếp luôn là 3 ký số, như TH009 cho người có họ tên là Hà Chính Thống
& người có tên Hoàng Thi có mã TH008,. . . .
Nhận việc này, bạn sẽ bắt đầu từ đâu? (Có nghĩa là định hướng giải quyết vấn đề này của bạn ra sao?)
Ta biết rằng trên diễn đàn thầy Phạm duy Long có hàm để tách tên trong họ tên tiếng Việt;
Vậy bạn è cổ ra viết lại từ đầu hay đi tìm trên diễn đàn thân thương của chúng ta, cái hàm mà bạn cần. Để rối tiếp theo ta cắt lấy ký tự đầu của hàm đó:

Ma=Ma & Left$(TachTen(HoTen),1) & Left$(HoTen,1) & "000"

Giống NDU đã nói, các tàu con thoi có thể cái chở người, cái chở nguyên liệu của sự sống cho con người & thiết bị lên ISS.
Nhưng & không bao giờ vừa chở người vừa chở hùm bà lằng những thứ khác nữa cả; chuyên biệt hoá & chuyên môn hoá từng Module, sẽ an toàn cho con người hơn gấp nhiều lần. Bạn cũng đã gặp từ này trong CS VBE chứ, nhỉ? . . . . Nó đó bạn!
. . . . .
 
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Nếu bạn muốn tìm hiểu thêm về chủ đề này, mời bạn xem bài http://www.giaiphapexcel.com/forum/showthread.php?53572-Thắc-mắc-về-hàm-UDF-UniqueList/page2 của sư phụ Ptm0412

Nhắc mới nhớ, Bài đó áp dụng tham số truyền là mảng tự gõ. Là thử nghiệm đầu tiên của lão chết tiệt với tham số là mảng tự gõ. Viết xong bài này Cò già ngẩn tò te luôn.

PHP:
Sub UniqueAndSum(sArray, ArrCols, UniqueCol, ArrSumCols)
  ...
End Sub

PHP:
Sub Test()
  Sheet2.Range("G1:K100").ClearContents
  Arr1 = Sheet1.Range("A2:G50001").Value
  UniqueAndSum Arr1, Array(2, 1, 0, 4, 0, 7, 6), 2, Array(6, 7) 

End Sub

Nghĩa là như ndu nói:
Không cần biết Sub UniqueAndSum nó phức tạp cỡ nào, viết ra làm sao, chỉ cần nhớ cú pháp là chạy từ bất kỳ nguồn dữ liệu nào ra mọi dạng kết quả mong muốn.
 
Lần chỉnh sửa cuối:
Upvote 0
Cho bạn thêm 1 ví dụ nữa về truyền tham số nè

PHP:
Sub KiemTraTenSheet()
  Dim SheetArr, Item As Variant
  SheetArr = Array("Time", "Data", "Cot", "Dam")
  For Each Item In SheetArr
    If SheetExist(Item) = False Then MsgBox "Sheet " & Item & " khong ton tai"
  Next
MsgBox "Da kiem tra xong"
End Sub

PHP:
Function SheetExist(ByVal WorkSheetName As String) As Boolean
  On Error Resume Next
  SheetExist = Not Sheets(WorkSheetName) Is Nothing
End Function

Tuy nhiên, nếu bạn muốn kiến thức của mình lên nhanh thì cần phải thực hành nhiều vào (những bài nào mà thuộc dạng mình gặp rồi thì cố gắng tự làm trước).

Cố gắng lên nhé./.
 
Upvote 0
Nhờ sửa giúp lỗi bài toán lọc duy nhất bằng truyền tham số

Hôm nay mới có thời gian, đọc các bài trên diễn đàn em thử làm bài toán lọc duy nhất bằng truyền tham số mà không được, rất mong các anh, chị các thày chỉ cho em chỗ sai

PHP:
Sub Filter(sArray As Range)
    Dim SubArr, Tmp
    Set Dic = CreateObject("Scripting.Dictionary")
    SubArr = sArray
    For Each Tmp In SubArr
        If Tmp <> "" And Not Dic.Exists(Tmp) Then
            Dic.Add Tmp, ""
        End If
    Next
End Sub

PHP:
Sub Main()
    ReDim Arr(1 To UBound(Dic.Keys, 1), 1 To 1)
    sArray = Sheet1.Range("A1:B1000")
    Call Filter
    Arr = Dic.Keys
    Sheets("sheet2").[A1].Resize(UBound(Dic.Keys, 1)).Value = Arr
End Sub
 
Upvote 0
Hôm nay mới có thời gian, đọc các bài trên diễn đàn em thử làm bài toán lọc duy nhất bằng truyền tham số mà không được, rất mong các anh, chị các thày chỉ cho em chỗ sai

PHP:
Sub Filter(sArray As Range)
    Dim SubArr, Tmp
    Set Dic = CreateObject("Scripting.Dictionary")
    SubArr = sArray
    For Each Tmp In SubArr
        If Tmp <> "" And Not Dic.Exists(Tmp) Then
            Dic.Add Tmp, ""
        End If
    Next
End Sub

PHP:
Sub Main()
    ReDim Arr(1 To UBound(Dic.Keys, 1), 1 To 1)
    sArray = Sheet1.Range("A1:B1000")
    Call Filter
    Arr = Dic.Keys
    Sheets("sheet2").[A1].Resize(UBound(Dic.Keys, 1)).Value = Arr
End Sub

Sub Filter có tham số truyền mà bạn gọi nó lại không truyền cho nó tham số? Đáng lẽ phải là Call Filter(sArray) chứ nhỉ?
 
Lần chỉnh sửa cuối:
Upvote 0
Phiền anh Kyo và mọi người sửa lại đúng giúp em để nó có thể chạy được ah
 
Upvote 0
Phiền anh Kyo và mọi người sửa lại đúng giúp em để nó có thể chạy được ah

Sửa lại cho bạn như vầy, có điều vì bạn dùng For Each nên mình chưa nghĩ ra được cách nào để bỏ cái Transpose, chứ nếu dùng For Next thì dễ hơn. Mong các cao thủ chỉ kyo dùng For Each mà vẫn không cần phải xài cái Transpose
PHP:
Public Dic
Sub Filter(sArray As String)
    Dim SubArr, Tmp
    Set Dic = CreateObject("Scripting.Dictionary")
    SubArr = Sheets("sheet1").Range(sArray).Value
    For Each Tmp In SubArr
        If Tmp <> "" And Not Dic.Exists(Tmp) Then
            Dic.Add Tmp, ""
        End If
    Next
End Sub

Sub Main()
Dim sArray As String
    sArray = "A1:B1000"
    Call Filter(sArray)
    ReDim Arr(1 To UBound(Dic.Keys, 1), 1 To 1)
    Arr = Dic.Keys
    Sheets("sheet2").[A1].Resize(UBound(Dic.Keys, 1)).Value = WorksheetFunction.Transpose(Arr)
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Sửa lại cho bạn như vầy, có điều vì bạn dùng For Each nên mình chưa nghĩ ra được cách nào để bỏ cái Transpose, chứ nếu dùng For Next thì dễ hơn. Mong các cao thủ chỉ kyo dùng For Each mà vẫn không cần phải xài cái Transpose

Em cũng rất muốn làm theo For Next mà chưa nghĩ ra, nếu có thể phiền anh giúp em thêm cách này.
 
Upvote 0
Sửa lại cho bạn như vầy, có điều vì bạn dùng For Each nên mình chưa nghĩ ra được cách nào để bỏ cái Transpose, chứ nếu dùng For Next thì dễ hơn. Mong các cao thủ chỉ kyo dùng For Each mà vẫn không cần phải xài cái Transpose
PHP:
Public Dic
Sub Filter(sArray As String)
    Dim SubArr, Tmp
    Set Dic = CreateObject("Scripting.Dictionary")
    SubArr = Sheets("sheet1").Range(sArray).Value
    For Each Tmp In SubArr
        If Tmp <> "" And Not Dic.Exists(Tmp) Then
            Dic.Add Tmp, ""
        End If
    Next
End Sub

Sub Main()
Dim sArray As String
    sArray = "A1:B1000"
    Call Filter(sArray)
    ReDim Arr(1 To UBound(Dic.Keys, 1), 1 To 1)
    Arr = Dic.Keys
    Sheets("sheet2").[A1].Resize(UBound(Dic.Keys, 1)).Value = WorksheetFunction.Transpose(Arr)
End Sub
Có thể là vầy cũng được:
PHP:
Public Arr(), lR As Long
Sub Filter(ByVal SrcRng As Range)
  Dim SubArr, tmpArr, Item, Dic As Object
  On Error Resume Next
  lR = 0
  If SrcRng.Count = 1 Then
    ReDim Arr(0)
    Arr(0) = SrcRng.Value
    lR = 1
  Else
    tmpArr = SrcRng.Value
    ReDim Arr(1 To SrcRng.Rows.Count * SrcRng.Columns.Count, 1 To 1)
    Set Dic = CreateObject("Scripting.Dictionary")
    For Each Item In tmpArr
      If CStr(Item) <> "" Then
        If Not Dic.Exists(CStr(Item)) Then
          lR = lR + 1
          Dic.Add CStr(Item), ""
          Arr(lR, 1) = Item
        End If
      End If
    Next
  End If
End Sub
PHP:
Sub Main()
  Dim SrcRng As Range
  Set SrcRng = Sheet1.Range("A1:B1000")
  Filter SrcRng
  If lR Then Sheet2.Range("A1").Resize(lR).Value = Arr
End Sub
 
Upvote 0
Thưa thày, ByVal trong câu này
PHP:
Sub Filter(ByVal SrcRng As Range)
nó có tác dụng gì so với việc không có tức chỉ ngắn gọn như thế này
PHP:
Sub Filter(SrcRng As Range)
 
Upvote 0
Tại sao mình dùng Dic.Keys lại phải có Transpose mới xong, trong khi của thày Ndu cũng hướng đi về cơ bản gần như vậy mà có cần Transpose đâu?
 
Upvote 0
Tại sao mình dùng Dic.Keys lại phải có Transpose mới xong, trong khi của thày Ndu cũng hướng đi về cơ bản gần như vậy mà có cần Transpose đâu?
Vì Dic.Keys là mảng 1 chiều, phải TRANSPOSE nó mới "lọt" đúng vào cột bảng tính (không TRANSPOSE nó sẽ "ngang" ra thành 1 dòng)
--------------------------------------
Thưa thày, ByVal trong câu này
PHP:
Sub Filter(ByVal SrcRng As Range)
nó có tác dụng gì so với việc không có tức chỉ ngắn gọn như thế này
PHP:
Sub Filter(SrcRng As Range)
Có 2 loại byVal và byRef.
Nếu không viết gì có nghĩa là byRef, trong khi byVal là thứ mà ta thường xài, vậy nên phải ghi cho rõ, tránh trường hợp sai lầm đáng tiếc trong các bài toán lớn hơn
Còn như bạn muốn biết byVal nó khác byRef chổ nào, hãy tham khảo các bài viết sau:
http://www.giaiphapexcel.com/forum/showthread.php?35509-Thảo-luận-mở-rộng-về-Useful-functions-Các-hàm-hữu-ích-của-Lê-Văn-Duyệt&p=235377#post235377
http://www.giaiphapexcel.com/forum/showthread.php?3976-Worksheet_SelectionChange(ByVal-Target-As-Range)&p=27667#post27667
http://www.giaiphapexcel.com/forum/showthread.php?1171-Hướng-dẫn-truyền-tham-số-bằng-giá-trị-(ByVal)
 
Lần chỉnh sửa cuối:
Upvote 0
Tại sao mình dùng Dic.Keys lại phải có Transpose mới xong, trong khi của thày Ndu cũng hướng đi về cơ bản gần như vậy mà có cần Transpose đâu?
Bạn có thể bỏ Transpose với code của kyo sẽ thấy lý do tại sao phải Transpose. Ở đây, Transpose có nghĩa là đảo mảng qua 90 độ, tức là từ ngang thành dọc. Do mảng Dic là mảng ngang nên xuất ra dọc thì sẽ không được nên phải dùng Transpose.
Với code của chú ndu thì chú đã dùng một mảng 2 chiều với chiều thứ nhất là chiều dọc dùng để add dữ liệu nên không cần phải Transpose

Trở về câu hỏi xài For ... Next thì kyo làm thế này, bạn xem được không nhé.
PHP:
Sub Filter(sArray As String)
    Dim SubArr, Arr
    If Sheets("Sheet1").Range(sArray).Count = 1 Then
        ReDim Arr(0)
        Arr(0) = Sheets("sheet1").Range(sArray).Value
        GoTo Finish
    End If
    Set Dic = CreateObject("Scripting.Dictionary")
    SubArr = Sheets("sheet1").Range(sArray).Value
    ReDim Arr(1 To UBound(SubArr, 1) * UBound(SubArr, 2), 1 To 1)
    For i = LBound(SubArr, 1) To UBound(SubArr, 1) * UBound(SubArr, 2)
        If i > UBound(SubArr, 1) Then
            If CStr(SubArr(i - UBound(SubArr, 1), 2)) <> "" And _
                    Not Dic.Exists(CStr(SubArr(i - UBound(SubArr, 1), 2))) Then
                Dic.Add CStr(SubArr(i - UBound(SubArr, 1), 2)), ""
                Arr(Dic.Count, 1) = SubArr(i - UBound(SubArr, 1), 2)
            End If
        Else
            If CStr(SubArr(i, 1)) <> "" And Not Dic.Exists(CStr(SubArr(i, 1))) Then
                Dic.Add CStr(SubArr(i, 1)), ""
                Arr(Dic.Count, 1) = SubArr(i, 1)
            End If
        End If
    Next
Finish:
    Sheets("sheet2").[A1].Resize(UBound(Dic.Keys, 1) + 1).Value = Arr
End Sub

Sub Main()
Dim sArray As String
    sArray = "A1:B1000"
    Call Filter(sArray)
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Nếu dùng For Each thì như ndu, nếu dùng For Next thì dùng 2 vòng For: 1 theo cột và 1 theo dòng, viết và đọc code sẽ đơn giản hơn.
Ngoài ra còn phải bẫy trường hợp sau khi thành 1 chiều, số dòng có vượt quá số dòng bảng tính hay không.
 
Upvote 0
Trở về câu hỏi xài For ... Next thì kyo làm thế này, bạn xem được không nhé.
PHP:
Sub Filter(sArray As String)
    Dim SubArr, Arr
    If Sheets("Sheet1").Range(sArray).Count = 1 Then
        ReDim Arr(0)
        Arr(0) = Sheets("sheet1").Range(sArray).Value
        GoTo Finish
    End If
    Set Dic = CreateObject("Scripting.Dictionary")
    SubArr = Sheets("sheet1").Range(sArray).Value
    ReDim Arr(1 To UBound(SubArr, 1) * UBound(SubArr, 2), 1 To 1)
    For i = LBound(SubArr, 1) To UBound(SubArr, 1) * UBound(SubArr, 2)
        If i > UBound(SubArr, 1) Then
            If CStr(SubArr(i - UBound(SubArr, 1), 2)) <> "" And Not Dic.Exists(CStr(SubArr(i - UBound(SubArr, 1), 2))) Then
                Dic.Add CStr(SubArr(i - UBound(SubArr, 1), 2)), ""
                Arr(Dic.Count, 1) = SubArr(i - UBound(SubArr, 1), 2)
            End If
        Else
            If CStr(SubArr(i, 1)) <> "" And Not Dic.Exists(CStr(SubArr(i, 1))) Then
                Dic.Add CStr(SubArr(i, 1)), ""
                Arr(Dic.Count, 1) = SubArr(i, 1)
            End If
        End If
    Next
Finish:
    Sheets("sheet2").[A1].Resize(UBound(Dic.Keys, 1) + 1).Value = Arr
End Sub

Sub Main()
Dim sArray As String
    sArray = "A1:B1000"
    Call Filter(sArray)
End Sub

Thật ra, nếu làm bài này với mục đích để xài thì nên:
- Chuyển Sub Filter thành Function ---> Kết quả của Function trả về sẽ là 1 Array (1 chiều hay 2 chiều tự ta quyết định)
- Đối số của Function sẽ là 1 Array thật sự chứ không nên là 1 chuổi chứa địa chỉ cell ---> Mục đích để có thể truyền vào nhiều kiểu dữ liệu hơn (Array hoặc Range tùy ý)
 
Upvote 0
Thật ra, nếu làm bài này với mục đích để xài thì nên:
- Chuyển Sub Filter thành Function ---> Kết quả của Function trả về sẽ là 1 Array (1 chiều hay 2 chiều tự ta quyết định)
- Đối số của Function sẽ là 1 Array thật sự chứ không nên là 1 chuổi chứa địa chỉ cell ---> Mục đích để có thể truyền vào nhiều kiểu dữ liệu hơn (Array hoặc Range tùy ý)

Vâng, cám ơn chú.
Tại vì mục đích của bạn Dauthivan muốn biết được cách truyền tham số nên kyo chỉ dựa trên sườn có sẵn của bạn ấy thôi chứ không có thay đổi cấu trúc có sẵn của bạn ấy chứ nếu mà làm luôn thì cũng không cần phải tách ra 2 Sub như vậy.

Với lại, kyo cũng muốn hỏi chú cách làm với array cũng dựa trên cấu trúc đó. Tức là như kyo là truyền biến string, chú giúp kyo truyền qua ParamArray được không?
 
Upvote 0
Với lại, kyo cũng muốn hỏi chú cách làm với array cũng dựa trên cấu trúc đó. Tức là như kyo là truyền biến string, chú giúp kyo truyền qua ParamArray được không?
Bài đó làm rồi mà kyo, chẳng hạn là bài này:
http://www.giaiphapexcel.com/forum/showthread.php?61993-Nhờ-lọc-dữ-liệu-duy-nhất-từ-2-cột-ra-1-cột-khác-bằng-VBA&p=381048#post381048
Một ứng dụng của nó để nạp List cho ComboBox như file đính kèm
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Web KT

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

Đếm ngược thời gian

000
Ngày
00
Giờ
00
phút
00
giây
Back
Top Bottom