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 làm theo For...Next mà không được, xin sửa lại đúng giúp em với ah.

PHP:
Sub Filter(ByVal sArray As Range)
    Dim SubArr, Arr, i As Long, j As Long, kk As Long
    SubArr = sArray
    Set Dic = CreateObject("Scripting.Dictionary")
    ReDim Arr(1 To UBound(SubArr, 1) * UBound(SubArr, 2), 1 To 1)
    For j = 1 To UBound(SubArr, 1)
        For j = 1 To UBound(Arr, 2)
            If SubArr(i, j) <> "" Then
                Tmp = SubArr(i, j)
                If Not Dic.Exists(Tmp) Then
                    kk = kk + 1
                    Dic.Add Tmp, kk
                    Arr(kk, 1) = Tmp
                End If
            End If
        Next j
    Next i
    Sheets("sheet2").[A1].Resize(kk).Value = Arr
End Sub

PHP:
Sub Main()
    Dim sArray As String
    sArray = Range("A1:B1000")
    Filter sArray
End Sub
 
Upvote 0
Em làm theo For...Next mà không được, xin sửa lại đúng giúp em với ah.

PHP:
Sub Filter(ByVal sArray As Range)
    Dim SubArr, Arr, i As Long, j As Long, kk As Long
    SubArr = sArray
    Set Dic = CreateObject("Scripting.Dictionary")
    ReDim Arr(1 To UBound(SubArr, 1) * UBound(SubArr, 2), 1 To 1)
    For j = 1 To UBound(SubArr, 1)
        For j = 1 To UBound(Arr, 2)
            If SubArr(i, j) <> "" Then
                Tmp = SubArr(i, j)
                If Not Dic.Exists(Tmp) Then
                    kk = kk + 1
                    Dic.Add Tmp, kk
                    Arr(kk, 1) = Tmp
                End If
            End If
        Next j
    Next i
    Sheets("sheet2").[A1].Resize(kk).Value = Arr
End Sub

PHP:
Sub Main()
    Dim sArray As String
    sArray = Range("A1:B1000")
    Filter sArray
End Sub
Sai mấy chổ:
For j = 1 To UBound(SubArr, 1) --> Lý ra phải là For i = 1 To UBound(SubArr, 1)
For j = 1 To UBound(Arr, 2) ---> Lý ra phải là For j = 1 To UBound(SubArr, 2)
Dim sArray As String ---> Ở trên khai báo sArray As Range sao ở dưới lại là String?
Ngoài ra, Sub Filter là sub viết ở mức tổng quát, vậy không nên có dòng Sheets("sheet2").[A1].Resize(kk).Value = Arr ---> Sao bạn biết chắc sẽ trích lọc kết quả vào sheet2, cell A1?
Vậy, sửa lại toàn bộ sẽ như vầy:
PHP:
Sub Filter(ByVal SrcRng As Range, ByVal Target As Range)
  Dim tmpArr, Arr(), lR As Long, lC As Long, kk As Long, Dic As Object, tmp
  On Error Resume Next
  tmpArr = SrcRng.Value
  Set Dic = CreateObject("Scripting.Dictionary")
  ReDim Arr(1 To UBound(tmpArr, 1) * UBound(tmpArr, 2), 1 To 1)
  For lR = 1 To UBound(tmpArr, 1)
    For lC = 1 To UBound(tmpArr, 2)
      If tmpArr(lR, lC) <> "" Then
        tmp = tmpArr(lR, lC)
        If Not Dic.Exists(tmp) Then
          kk = kk + 1
          Dic.Add tmp, kk
          Arr(kk, 1) = tmp
        End If
      End If
    Next
  Next
  If kk Then Target.Resize(kk).Value = Arr
End Sub
PHP:
Sub Main()
  Dim SrcRng As Range, Target As Range
  Set SrcRng = Sheet1.Range("A1:B1000")
  On Error Resume Next
  Set Target = Sheet2.Range("A1")
  Filter SrcRng, Target
End Sub
Lưu ý: Nếu viết như vầy thì chỉ hoạt động với nguồn dữ liệu là Range thôi nha
 
Upvote 0
Lưu ý: Nếu viết như vầy thì chỉ hoạt động với nguồn dữ liệu là Range thôi nha

Em vẫn chưa hiểu hết ý thày ở trên, rất mong thày giúp em bẫy các lỗi, để nó được áp dụng trong trường hợp tổng quát.
 
Upvote 0
Em vẫn chưa hiểu hết ý thày ở trên, rất mong thày giúp em bẫy các lỗi, để nó được áp dụng trong trường hợp tổng quát.

Thì do khai báo SrcRng as Range, đương nhiên dữ liệu đầu vào sẽ là Range thôi
Muốn tổng quát cho Range và Array, khai báo lại biến này... Nhưng nói trước là không dễ ăn, vì đã là Array thì bạn đâu biết trước nó 1 chiều hay 2 chiều... Vậy bằng cách nào để ReDim Arr cho đúng kích thước? (ít nhất là không bị thiếu)
 
Upvote 0
Em vẫn chưa hiểu hết ý thày ở trên, rất mong thày giúp em bẫy các lỗi, để nó được áp dụng trong trường hợp tổng quát.
Thôi, làm cho bạn luôn đây!
1> Đầu tiên phải viết 1 hàm hổ trợ để tính số phần tử trong Array
PHP:
Function Elements(ByVal sArray) As Long
  Dim lEs As Long, lDim As Long, tmpArr
  On Error Resume Next
  tmpArr = sArray
  lEs = 1
  If IsArray(tmpArr) Then
    Do While Err.Number = 0
      lDim = lDim + 1
      lEs = lEs * (UBound(tmpArr, lDim) - LBound(tmpArr, lDim) + 1)
    Loop
    Elements = lEs
  End If
End Function
2> Sub Filter sửa lại:
PHP:
Sub Filter(ByVal sArray, ByVal Target As Range)
  Dim tmpArr, Arr(), lEs As Long, Item, lR As Long, Dic As Object, tmp
  On Error Resume Next
  tmpArr = sArray
  If TypeName(tmpArr) <> "Variant()" Then
    Target(1, 1).Value = tmpArr
  Else
    lEs = Elements(tmpArr)
    Set Dic = CreateObject("Scripting.Dictionary")
    ReDim Arr(1 To lEs, 1 To 1)
    For Each Item In tmpArr
      If CStr(Item) <> "" Then
        tmp = CStr(Item)
        If Not Dic.Exists(tmp) Then
          lR = lR + 1
          Dic.Add tmp, lR
          Arr(lR, 1) = Item
        End If
      End If
    Next
    If lR Then Target.Resize(lR).Value = Arr
  End If
End Sub
3> Code chính:
PHP:
Sub Main()
  Dim sArray, Target As Range
  sArray = Sheet1.Range("A1:B1000").Value
  On Error Resume Next
  Set Target = Sheet2.Range("A1")
  Filter sArray, Target
End Sub
Code trên chạy được với dữ liệu nguồn là Range, mảng 1 chiều hoặc nhiều chiều
Tự bạn nghiên cứu code trên nhé! Chỉ lưu ý điểm này:
- Tôi đặt tmp = CStr(Item) ---> Xét tmp theo dạng chuổi
- Add tmp vào Dic bằng code Dic.Add tmp, lR
- Nhưng tôi không nạp tmp mà lại nạp Item vào Arr (Arr(lR, 1) = Item)
Lý do vì có trường hợp thế này:
- Cell A1 ta có số 1 định dạng Text
- Cell A2 ta có số 1 định dạng Number
Trường hợp này thì code trên sẽ xem 2 "thằng" này là 1 và sẽ Add vào Dic 1 cái thôi
---------------
Còn vụ If TypeName(tmpArr) <> "Variant()" Then hình như có lần tôi đã nói rồi
 
Upvote 0
Em chưa hiểu tại sao lại phải tính số phần tử Array hả thày?

PHP:
lEs = Elements(tmpArr)
....
ReDim Arr(1 To lEs, 1 To 1)
Mục đích khi tính số phần tử Array là để Redim cho chính xác, nhất là tránh trường hợp Redim thiếu
 
Upvote 0
Trình độ em còn CÒI quá, chưa biết nhiều thứ, xin thày cho em hỏi

PHP:
If TypeName(tmpArr) <> "Variant()" Then
    Target(1, 1).Value = tmpArr
nó có ý nghĩa gì?

-----------------
Em thắc mắc là sArray = Sheet1.Range("A1:B1000").Value có nghĩa sArray nó là mảng rồi thì cần gì phải làm động tác thêm biến tmpArr (= sArray) làm gì ah.

Hay là đoạn bôi đỏ theo cách hiểu của em như vầy là sai?
 
Lần chỉnh sửa cuối:
Upvote 0
Trình độ em còn CÒI quá, chưa biết nhiều thứ, xin thày cho em hỏi

PHP:
If TypeName(tmpArr) <> "Variant()" Then
    Target(1, 1).Value = tmpArr
nó có ý nghĩa gì?

-----------------
Em thắc mắc là sArray = Sheet1.Range("A1:B1000").Value có nghĩa sArray nó là mảng rồi thì cần gì phải làm động tác thêm biến tmpArr (= sArray) làm gì ah.

Hay là đoạn bôi đỏ theo cách hiểu của em như vầy là sai?
- Câu 1: Lở sArray chỉ là 1 cell thì sao? Dẫn đến tmpArr không phải là Array (mà là 1 giá trị đơn)
- Câu 2: Lở như khi áp dụng người ta ghi Set sArray = Sheet1.Range("A1:B1000") thì sao? Tức người ta truyền Range vào chứ không phải Array ----> Phòng ngừa: Nếu người ta truyền vào là 1 Array thì động tác tmpArr = sArray là dư nhưng nếu người ta truyền vào 1 Range, thì động tác tmpArr = sArray nhằm mục đích chuyển sArray sang Array thật sự
-----------------------
Cái này tôi đã nói mấy lần rồi nhưng hình như bạn không để ý
 
Upvote 0
Vì bận quá, không chịu tìm trên diễn đàn nên không biết là thày đã nói về vấn đề trên rồi.

Em vẫn chưa hiểu kỹ sự khác nhau giữa cách dùng Funtion và Sub trong bài này, cụ thể: Hai Code trên dùng Function nó có ưu điểm gì so với dùng Sub ah?
 
Upvote 0
Vì bận quá, không chịu tìm trên diễn đàn nên không biết là thày đã nói về vấn đề trên rồi.

Em vẫn chưa hiểu kỹ sự khác nhau giữa cách dùng Funtion và Sub trong bài này, cụ thể: Hai Code trên dùng Function nó có ưu điểm gì so với dùng Sub ah?
- Sub dùng để thực thi công việc nào đó (ví dụ tô màu, kẻ khung, gán 1 giá trị vào 1 vùng...) ---> Ví thế Sub có tham số sẽ có dạng
Mã:
Sub TENSUB(Đối số)
'' Thực thi công việc
End Sub
- Function sẽ trả về 1 kết quả sau quá trình tính toán ---> Ví thế bạn sẽ luôn thấy Function có dạng thế này
Mã:
Function TENHAM(Đối số) [COLOR=#ff0000]As Kiểu dữ liệu[/COLOR]
'' Tính toán gì đó
[COLOR=#ff0000]TENHAM = Kết quả tính toán[/COLOR]
End Function
Chổ tô đỏ là cái khác nhau giữa Sub và Function đấy
Ngoài ra, với 1 Function thì bạn có thể áp dụng trực tiếp trên bảng tính bằng cách gõ vào 1 cell nào đó (như hàm có sẵn của Excel) còn Sub thì không thể dùng cách này
------------------------------
Không thể nói cái nào có ưu điêm hơn, tùy theo yêu cầu mà chọn lựa hợp lý thôi
 
Lần chỉnh sửa cuối:
Upvote 0
Chán quá, thực hành lại từ bài đơn giản trước, bắt chước giống thày Ndu kiểm tra lại từng dòng rồi mà không hiểu sao Code chạy lại chẳng ra cái gì

PHP:
Sub Filter(SrcRng As Range)
    Dim Arr(), TmpArr, lR As Long, lC As Long, kk As Long, Dic As Object
    TmpArr = SrcRng
    ReDim Arr(1 To UBound(TmpArr, 1) * UBound(TmpArr, 2), 1 To 1)
    Set Dic = CreateObject("Scripting.Dictionary")
    For lC = 1 To UBound(TmpArr, 2)
        For lR = 1 To UBound(TmpArr, 1)
            If TmpArr(lR, lC) <> "" Then
                Tmp = TmpArr(lR, lC)
                If Not Dic.Exists(Tmp) Then
                    kk = kk + 1
                    Dic.Add Tmp, kk
                    Arr(kk, 1) = Tmp
                End If
            End If
        Next lR
    Next lC
End Sub

PHP:
Sub Main()
    Dim SrcRng As Range
    Set SrcRng = Sheet1.Range("A1:B1000")
    Filter SrcRng
    If kk Then Sheet2.[A1].Resize(kk).Value = Arr
End Sub
 
Upvote 0
Chán quá, thực hành lại từ bài đơn giản trước, bắt chước giống thày Ndu kiểm tra lại từng dòng rồi mà không hiểu sao Code chạy lại chẳng ra cái gì

PHP:
Sub Filter(SrcRng As Range)
    Dim Arr(), TmpArr, lR As Long, lC As Long, kk As Long, Dic As Object
    TmpArr = SrcRng
    ReDim Arr(1 To UBound(TmpArr, 1) * UBound(TmpArr, 2), 1 To 1)
    Set Dic = CreateObject("Scripting.Dictionary")
    For lC = 1 To UBound(TmpArr, 2)
        For lR = 1 To UBound(TmpArr, 1)
            If TmpArr(lR, lC) <> "" Then
                Tmp = TmpArr(lR, lC)
                If Not Dic.Exists(Tmp) Then
                    kk = kk + 1
                    Dic.Add Tmp, kk
                    Arr(kk, 1) = Tmp
                End If
            End If
        Next lR
    Next lC
End Sub

PHP:
Sub Main()
    Dim SrcRng As Range
    Set SrcRng = Sheet1.Range("A1:B1000")
    Filter SrcRng
    If kk Then Sheet2.[A1].Resize(kk).Value = Arr
End Sub
Như đã nói: Sub là để thực thi công việc nào đó... Vậy bạn nhìn lại Sub Filter của bạn xem, nó có thực thi 1 hành động cụ thể nào đâu? Sau khi Add Dic, nạp Arrary.. vân vân... thì chẳng làm cái gì cả ---> Lý ra, cuối cùng phải gán mảng kết quả vào sheet chứ
Còn Sub Main lại có câu If kk Then Sheet2.[A1].Resize(kk).Value = Arr ---> Chẳng có ý nghĩa gì cả! kk là cái gì? Arr là cái gì?
--------------
Mà bài này tôi đã viết rất rõ rồi còn gì:
PHP:
Sub Filter(ByVal SrcRng As Range, ByVal Target As Range)
  Dim Arr(), tmpArr, lR As Long, lC As Long, kk As Long, Dic As Object, tmp
  tmpArr = SrcRng
  ReDim Arr(1 To UBound(tmpArr, 1) * UBound(tmpArr, 2), 1 To 1)
  Set Dic = CreateObject("Scripting.Dictionary")
  For lC = 1 To UBound(tmpArr, 2)
    For lR = 1 To UBound(tmpArr, 1)
      If tmpArr(lR, lC) <> "" Then
        tmp = tmpArr(lR, lC)
        If Not Dic.Exists(tmp) Then
          kk = kk + 1
          Dic.Add tmp, kk
          Arr(kk, 1) = tmp
        End If
       End If
     Next lR
  Next lC
  If kk Then Target.Resize(kk).Value = Arr
End Sub
PHP:
Sub Main()
  Dim SrcRng As Range, Target As Range
  Set SrcRng = Sheet1.Range("A1:B1000")
  Set Target = Sheet2.Range("A1")
  Filter SrcRng, Target
End Sub
----------------
Hoặc nếu giữ nguyên code của bạn thì phải cho biến Arr() và kk lên thành Public
PHP:
Public Arr(), kk As Long
Sub Filter(SrcRng As Range)
  Dim TmpArr, lR As Long, lC As Long, Dic As Object, tmp
  TmpArr = SrcRng
  kk = 0
  ReDim Arr(1 To UBound(TmpArr, 1) * UBound(TmpArr, 2), 1 To 1)
  Set Dic = CreateObject("Scripting.Dictionary")
  For lC = 1 To UBound(TmpArr, 2)
    For lR = 1 To UBound(TmpArr, 1)
      If TmpArr(lR, lC) <> "" Then
        tmp = TmpArr(lR, lC)
        If Not Dic.Exists(tmp) Then
          kk = kk + 1
          Dic.Add tmp, kk
          Arr(kk, 1) = tmp
        End If
      End If
    Next lR
  Next lC
End Sub
PHP:
Sub Main()
  Dim SrcRng As Range
  Set SrcRng = Sheet1.Range("A1:B1000")
  Filter SrcRng
  If kk Then Sheet2.[A1].Resize(kk).Value = Arr
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Em tưởng câu này
PHP:
Arr(kk, 1) = tmp
cũng là thực thi hành động nào đó rồi?


PHP:
Filter SrcRng
Bởi em nghĩ sau khi có câu lệnh trên, 2 Sub liên kết với nhau rồi thì thì Sub Main nó tự biết kk là cái gì từ Sub trên chứ ah?
PHP:
    If kk Then Sheet2.[A1].Resize(kk).Value = Arr
 
Upvote 0
Em tưởng câu này
PHP:
Arr(kk, 1) = tmp
cũng là thực thi hành động nào đó rồi?


PHP:
Filter SrcRng
Bởi em nghĩ sau khi có câu lệnh trên, 2 Sub liên kết với nhau rồi thì thì Sub Main nó tự biết kk là cái gì từ Sub trên chứ ah?
PHP:
    If kk Then Sheet2.[A1].Resize(kk).Value = Arr
Cấu lệnh Arr(kk, 1) = tmp gì gì đó chỉ có thể xem là "thực thi trên giấy"... Muốn kết quả cụ thể phải có hành động cụ thể (bằng động tác gán xuống sheet chẳng hạn)
Sub của bạn phải làm được 1 trong 2 việc sau đây:
- Thực thi 1 hành động cụ thể nào đó (đoạn code thứ nhất của tôi là gán xuống sheet bằng lệnh Target.Resize(kk).Value = Arr)
- Sinh ra 1 sản phẩm nào đó (đoạn code thứ 2 của tôi, sản phẩm sinh ra chính là biến Arr được khai báo dạng Public)
Nói thêm:
- Khi bạn để biến Arr bên trong Sub Filter thì sẽ không thể dùng biến này trong 1 sub khác được, tức nó sẽ chẳng biết Arr, kk là cái giống gì cả...
- Muốn lấy kết quả từ biến Arr, phải khai báo nó dạng Public (để sau khi chạy code, biến này còn lưu giữ được giá trị cuối cùng)
 
Upvote 0
Vâng, nhận thức của em ngây thơ quá, tưởng Sub trên làm công việc đến đâu thì làm, phần công việc còn lại Sub dưới "làm nốt". Tức là tựa như quyển sách vậy, 2 Sub trên như là 2 chương còn việc phân chia nội dung cho vào Chương nào cũng được, miễn sao tổng không đổi.

Nghe thày nói em đã hình dung ra được 1 chút, em xin hỏi tác dụng của Public là gì thế (em chỉ biết nghĩa Tiếng Việt của nó là công khai thôi)?
 
Upvote 0
Nghe thày nói em đã hình dung ra được 1 chút, em xin hỏi tác dụng của Public là gì thế (em chỉ biết nghĩa Tiếng Việt của nó là công khai thôi)?

Nguyên văn bởi ndu:
Muốn lấy kết quả từ biến Arr, phải khai báo nó dạng Public (để sau khi chạy code, biến này còn lưu giữ được giá trị cuối cùng)

Ngược lại:
Nếu không khai báo dạng Public, ...
 
Upvote 0
Vâng, nhận thức của em ngây thơ quá, tưởng Sub trên làm công việc đến đâu thì làm, phần công việc còn lại Sub dưới "làm nốt". Tức là tựa như quyển sách vậy, 2 Sub trên như là 2 chương còn việc phân chia nội dung cho vào Chương nào cũng được, miễn sao tổng không đổi.

Nghe thày nói em đã hình dung ra được 1 chút, em xin hỏi tác dụng của Public là gì thế (em chỉ biết nghĩa Tiếng Việt của nó là công khai thôi)?
Nhớ có lần tôi đã hình dung thế này:
- Public = công cộng ---> Vậy thì ai xài cũng được (tức "đứng" từ sub khác hoặc 1 module khác cũng có thể dùng được cái Public do thằng ở sub này hoặc module xây dựng nên)
- Private = riêng tư ---> Mạnh ai nấy xài
Vậy thôi
---------
Cũng giống như:
- Arr là cái kho gạo công cộng (Public), thằng Sub Filter sau khi chạy xong, sẽ "đổ gạo" vào kho công cộng này nên thằng Sub Main sẽ đến lấy được gạo về nấu
- Nếu Arr là biến nằm trong sub Filter, tức là gạo của riêng nó ---> Thằng Sub Main đến lấy, nó đánh bỏ xừ...
Ẹc... Ẹc...
 
Lần chỉnh sửa cuối:
Upvote 0
Nhớ có lần tôi đã hình dung thế này:
- Public = công cộng ---> Vậy thì ai xài cũng được (tức "đứng" từ sub khác cũng có thể dùng được cái Public do thằng khác xây dựng nên)
- Private = riêng tư ---> Của ai nấy xài
Vậy thôi

Nếu nhớ lại nguyên văn thì lúc đó ndu dùng thí dụ cái toilet cơ.
Hic, spam cái. Công nhận vài hôm nay ndu quá kiên nhẫn.
Chứ có một câu ngắn như vậy, 1 là không đọc, 2 là đọc không hiểu, lão chết tiệt chịu, bó tay.
 
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