Các câu hỏi về mảng trong VBA (Array)

Liên hệ QC

viehoai

Thành viên gắn bó
Tham gia
22/5/09
Bài viết
2,600
Được thích
2,907
Xin các anh chị giúp đỡ Code Gán các giá trị của một Range là các phần tử của Mãng
Ví dụ: Tôi có các giá trị của Range("A1:A10"). Tôi muốn viết code để gán giá trị của các cells từ A1:A10 là các phần tử của Mãng Arr chẳn hạn.
Xin cảm ơn các anh chị
 
Từ code của bác, tôi thắc mắc liệu cách dùng trong bài giải của bác có gì khác nếu viết thành thế này không?

Sub Chanqua()
Dim DL, Thang, Dongdau As Long, Dongcuoi As Long, i As Long
Dongdau = 3
Dongcuoi = [A65000].End(xlUp).Row
DL = Range("A" & (Dongdau) & ":A" & Dongcuoi).Value
Thang = Range("B" & (Dongdau) & ":B" & Dongcuoi).Value
For i = Dongdau To UBound(DL, 1)
Thang(i, 1) = DL(i, 1)
Next i
Range("B" & (Dongdau) & ":B" & Dongcuoi).Value = Thang
End Sub
Bạn nên nhớ rằng khi chuyển bất cứ Range vào sang Array thì chỉ số của phần tử đầu tiên trong Array luôn bắt đầu bằng 1
Ở đây bạn chuyên vùng A3:Ax sang Array DL, với vùng A3:Ax bắt đầu từ dòng 3, nhưng DL lại bắt đầu bằng 1 (cả Thang cũng bắt đầu bằng 1)
Vậy nếu dùng code trên, bạn sẽ bị mất 2 phần tử 1 và 2
Bởi vậy phải sửa thành:
Mã:
Sub Chanqua()
  Dim DL, Thang, Dongdau As Long, Dongcuoi As Long, i As Long
  Dongdau = 3
  Dongcuoi = [A65000].End(xlUp).Row
  DL = Range("A" & (Dongdau) & ":A" & Dongcuoi).Value
  Thang = Range("B" & (Dongdau) & ":B" & Dongcuoi).Value
  For [COLOR=#ff0000][B]i = 1[/B][/COLOR] To UBound(DL, 1)
    Thang(i, 1) = DL(i, 1)
    Next i
  Range("B" & (Dongdau) & ":B" & Dongcuoi).Value = Thang
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Ah, Tôi hiểu rồi.

Thế thì thực chất đoạn ReDim Thang(1 To UBound(DL, 1), 1 To 1) nó chẳng qua thay thế cho đoạn Thang = Range("B" & (Dongdau) & ":B" & Dongcuoi).Value, nhưng Redim có ưu điểm là có tính tự động co dãn để đảm bảo số phần tử của Thang luôn = số phần tử của DL?
 
Lần chỉnh sửa cuối:
Upvote 0
Ah, Tôi hiểu rồi.

Thế thì thực chất đoạn ReDim Thang(1 To UBound(DL, 1), 1 To 1) nó chẳng qua thay thế cho đoạn Thang = Range("B" & (Dongdau) & ":B" & Dongcuoi).Value, nhưng Redim có ưu điểm là có tính tự động co dãn để đảm bảo số phần tử của Thang luôn = số phần tử của DL?

Đã co giãn rồi sao có thể đảm bảo số phần tử của mảng ban đầu bằng với mảng mới được bạn? Muốn bằng hay không do mình quy định khi ReDim thôi bạn à.
 
Upvote 0
Cuối ngày rồi mình có 1 câu hỏi muốn hỏi các bạn ham thích về mảng Array cũng để các bạn hiểu rõ hơn về mảng Array
PHP:
Sub ArrinArr()
Dim Arr As Variant
Arr = Array(Array(Array(4, 5, 6), Array(7, 8, 9), Array(10, 11, 12)), Array(4, Array(13, 14, 15), 6))
'Debug.Print Arr(1)(1)(1)
End Sub
Bạn suy nghĩ trường hợp không dùng Option Base 1 thì truy xuất phần tử trong Array với kiểu truy xuất như dạng này Arr(1)(1)(1) thì giá trị là bao nhiêu, rồi dùng Option Base 1 thì giá trị là bao nhiêu suy nghĩ rồi thì bạn hãy dùng Debug.Print nhen! Các bạn cứ phát triển thêm phần tử trong mảng để hiểu rõ hơn
 
Upvote 0
Cuối ngày rồi mình có 1 câu hỏi muốn hỏi các bạn ham thích về mảng Array cũng để các bạn hiểu rõ hơn về mảng Array
PHP:
Sub ArrinArr()
Dim Arr As Variant
Arr = Array(Array(Array(4, 5, 6), Array(7, 8, 9), Array(10, 11, 12)), Array(4, Array(13, 14, 15), 6))
'Debug.Print Arr(1)(1)(1)
End Sub
Bạn suy nghĩ trường hợp không dùng Option Base 1 thì truy xuất phần tử trong Array với kiểu truy xuất như dạng này Arr(1)(1)(1) thì giá trị là bao nhiêu, rồi dùng Option Base 1 thì giá trị là bao nhiêu suy nghĩ rồi thì bạn hãy dùng Debug.Print nhen! Các bạn cứ phát triển thêm phần tử trong mảng để hiểu rõ hơn
Ẹc... Ẹc... không ngở bạn cũng bắt đầu nghiên cứu đến phần "cao cấp" của mảng đây: Mảng trong mảng ---> Trò này sẽ có nhiều ứng dụng rất hay!
 
Upvote 0
Ẹc... Ẹc... không ngở bạn cũng bắt đầu nghiên cứu đến phần "cao cấp" của mảng đây: Mảng trong mảng ---> Trò này sẽ có nhiều ứng dụng rất hay!
Em xin đưa 1 file mảng trong mảng mình tập làm quen thôi chứ không ứng dụng gì hết, anh Ndu giúp em cho em 1 vài ứng dụng đi nhen

PHP:
Sub ArrayinArray()
Dim arr(3) As Variant
Dim icol As Long, i As Long, j As Long
With Sheets("data")
    For icol = 1 To 8 Step 3
        i = i + 1
        arr(i) = .Range(.Cells(1, icol), .Cells(21, icol)).Resize(, 2).Value
    Next
    For i = 1 To UBound(arr(2))
        If Len(arr(2)(i, 2)) = 10 Then
            j = j + 1
            arr(3)(j, 1) = arr(2)(i, 2)
        End If
    Next i
.Range("i2").Resize(j, 1).Value = arr(3)
End With
End Sub
Trong ví dụ này chủ yếu các giá trị ta nạp chúng vào Array tạm rồi xuất giá trị theo từng lần nạp theo thứ tự dòng cột mà chúng ta muốn xuất ví dụ ta lấy các giá trị có chiều dài bằng 10 của lần nạp thứ 2 của cột thứ 2
 

File đính kèm

  • ArrayinArray.xls
    49.5 KB · Đọc: 78
Upvote 0
Em xin đưa 1 file mảng trong mảng mình tập làm quen thôi chứ không ứng dụng gì hết, anh Ndu giúp em cho em 1 vài ứng dụng đi nhen
Ứng dùng là bài này nè (vửa đố xong):
http://www.giaiphapexcel.com/forum/showthread.php?60569-HD-giúp-thuật-toán-tìm-cặp-số-liên-tiếp-thỏa-dk!&p=374182#post374182
Tôi làm như sau:
PHP:
Option Base 1
Sub ConsNum(ByVal numArr)
  Dim Dic1, Dic2, ArrItem(1 To 2), Arr(), TG As Double
  Dim k As Long, tmp, lPos As Long, n As Long
  TG = Timer
  Set Dic1 = CreateObject("Scripting.Dictionary")
  Set Dic2 = CreateObject("Scripting.Dictionary")
  For k = LBound(numArr) To UBound(numArr) - 1
    If numArr(k) > 1 And numArr(k + 1) > 1 Then
      If lPos = 0 Then lPos = k
      If Not Dic1.Exists(lPos) Then
        n = n + 1
        Dic1.Add lPos, 2
        Dic2.Add lPos, n
        ReDim Preserve Arr(1 To n)
        Arr(n) = ArrItem
        Arr(n)(1) = lPos
        Arr(n)(2) = 2
      Else
        Dic1.Item(lPos) = Dic1.Item(lPos) + 1
        Arr(Dic2.Item(lPos))(1) = lPos
        Arr(Dic2.Item(lPos))(2) = Dic1.Item(lPos)
      End If
    Else
      lPos = 0
    End If
    tmp = numArr(k)
  Next
  For k = 1 To UBound(Arr)
    Arr(k) = Join(Arr(k), ":")
  Next
  If n Then Range("C1").Value = Join(Arr, " - ")
  MsgBox Timer - TG
End Sub
PHP:
Function Range2Array(ByVal SrcRng As Range)
  Dim Item, sArray, Arr(), n As Long
  sArray = SrcRng.Value
  ReDim Arr(SrcRng.Count)
  For Each Item In SrcRng
    n = n + 1
    Arr(n) = Item
  Next
  Range2Array = Arr
End Function
PHP:
Sub Main()
  Dim i As Long, numArr
  numArr = Range2Array(Range("A1:A10000"))
  ConsNum numArr
End Sub
Xem file đính kèm, dữ liệu nguồn tại cột A
 

File đính kèm

  • Book1.rar
    75.3 KB · Đọc: 117
Upvote 0
Tôi vẫn chưa hiểu được hết bản chất của mảng, xin được chỉ giúp chố sai của đoạn Code này

PHP:
Sub loc()
  Dim Vung
        Set Vung = Range([A1], [A65000].End(xlUp))
  i = Count(Vung)
    MsgBox i
   End Sub

Nếu khai báo đoạn Set Vung = Range([A1], [A65000].End(xlUp)) bằng đoạn Vung = Range([A1], [A65000].End(xlUp)) thì có gì là khác nhau?

Xin cảm ơn rất nhiều./.
 
Upvote 0
Tôi vẫn chưa hiểu được hết bản chất của mảng, xin được chỉ giúp chố sai của đoạn Code này

PHP:
Sub loc()
  Dim Vung
        Set Vung = Range([A1], [A65000].End(xlUp))
  i = Count(Vung)
    MsgBox i
   End Sub

Nếu khai báo đoạn Set Vung = Range([A1], [A65000].End(xlUp)) bằng đoạn Vung = Range([A1], [A65000].End(xlUp)) thì có gì là khác nhau?

Xin cảm ơn rất nhiều./.
Theo như mình hiểu thì Vung là mãng nhận giá trị trong vùng đó, còn Set Vung là bao gồm mãng, định dạng v.v...
 
Upvote 0
Tôi vẫn chưa hiểu được hết bản chất của mảng, xin được chỉ giúp chố sai của đoạn Code này

PHP:
Sub loc()
  Dim Vung
        Set Vung = Range([A1], [A65000].End(xlUp))
  i = Count(Vung)
    MsgBox i
   End Sub

Nếu khai báo đoạn Set Vung = Range([A1], [A65000].End(xlUp)) bằng đoạn Vung = Range([A1], [A65000].End(xlUp)) thì có gì là khác nhau?

Xin cảm ơn rất nhiều./.

Bạn chưa đúng cơ bản 2 điều:

1) Khi dùng Set đối với vùng giá trị nào đó của sheet, nó thuộc về biến Range, còn không Set nó như là 1 Variant

2) Trong thủ tục code không có cấu trúc: Count(Vung) mà nếu đã Set Vung as Range thì ta có thể ghi là Vung.Count, với mảng có lẽ ta phải dùng thủ tục Ubound để đếm.

Bạn xem 2 thủ tục ít nhiều sẽ rõ:

Với Vung là một Range:
PHP:
Sub loc1()
    Dim Vung As Range
    Set Vung = Range([A1], [A65000].End(xlUp))
    i = Vung.Count
    MsgBox i
End Sub

Với Vung là một Variant (có thể phát sinh lỗi nếu i bằng 0 hoặc bằng 1):
PHP:
Sub loc2()
    Dim Vung As Variant
    Vung = Range([A1], [A65000].End(xlUp))
    i = UBound(Vung, 1)
    MsgBox i
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Xin hỏi thêm: Làm thế nào để đếm nhanh được số phần tử trong vung không tính ô trống (tức là MsgBox i = 5 thay vì bằng 6 như các đoạn Code trên).
 
Upvote 0
Xin hỏi thêm: Làm thế nào để đếm nhanh được số phần tử trong vung không tính ô trống (tức là MsgBox i = 5 thay vì bằng 6 như các đoạn Code trên).

Thì bạn làm như vầy đi:

PHP:
Sub loc2()
    Dim Vung, i As Long, m As Long
    Vung = Range([A1], [A65000].End(xlUp))
    For i = 1 To UBound(Vung)
        If Vung(i, 1) <> "" Then m = m + 1
    Next i
    MsgBox m
End Sub
 
Upvote 0
Tôi vẫn còn lờ mờ cái này: Chưa phần biệt được khác nhau, cách dùng giữa RangeVariant.
Nhờ bác minhthien321 và mọi người giúp cho.
 
Upvote 0
Tôi vẫn còn lờ mờ cái này: Chưa phần biệt được khác nhau, cách dùng giữa RangeVariant.
Nhờ bác minhthien321 và mọi người giúp cho.

Để giải thích theo kiểu nôm na của mình hiểu thì:

1) Range: là kiểu dữ liệu dựa trên sheet, nó mang tính chất của một Range khi được khai báo

2) Variant: là kiểu dữ liệu bất kỳ, nó bao gồm tất cả các biến được khai như: Integer, Byte, Long, Single, Currency, Decimal, Double...

Nếu Set Vung = [A1:G300] thì nó mang tính chất Range, những thuộc tính của Range như thế nào thì Vung đều có như thế đó.

Nếu Vung = [A1:G300] thì nó như là một mảng, chỉ mang giá trị là Value chứ không có các thuộc tính như Range.
 
Upvote 0
Một đề tài rất hay, nhờ đọc nó em thấy hiểu thêm được rất nhiều điều. Em xin cảm ơn các sư phụ Ptm0412, sư phụ Ndu96081631 rất nhiều.
 
Upvote 0
Xin chỉ rõ hơn 1 chút, tôi vẫn loay hoay phân biệt cách dùng Range và Variant.

Tại sao viết thế này không chạy
PHP:
Sub loc1()
    Dim Vung As Range
    Vung = Range([A1], [A65000].End(xlUp))
    i = Vung.Count
    MsgBox i
End Sub

Đổi thành thế này lại OK
PHP:
Sub loc()
  Dim Vung
        Set Vung = Range([A1], [A65000].End(xlUp))
  i = Count(Vung)
    MsgBox i
   End Sub
lại được.

(Bởi tôi cứ hay nhầm cách sử dụng Count và Ubound), do IQ của tôi tiếp thu chậm quá, xin mọi người giảng giải cho.
---------------------

Ah, tôi hiểu ra thế này, nếu có gì sai nhờ mọi người sửa hộ

Bản chất của Count là đếm số ô, mà Range chứa các ô nên nó là đối tượng của Count. Trong khi Vung trong Code thứ nhất khi khai báo dạng Variant nên nó chỉ là các giá trị "rời rạc" không liên quan đến khái niệm ô nên không phải là đối tượng của Count.

Ubound có tính chất đếm số phần tử trong tập rời rạc nên nó làm việc với Variant (chứ không phải đếm ô nên không làm việc với Range tức là TH khai báo Set).

Khi so sánh, làm phép tính phải sử dụng Variant (chứ không sử dụng trực tiếp Range), chỉ khi ra kết quả cuối cùng gán cho 1 vùng lúc này mới sử dụng Range chăng?
 
Lần chỉnh sửa cuối:
Upvote 0
Xin chỉ rõ hơn 1 chút, tôi vẫn loay hoay phân biệt cách dùng Range và Variant.

Tại sao viết thế này không chạy
PHP:
Sub loc1()
    Dim Vung As Range
    Vung = Range([A1], [A65000].End(xlUp))
    i = Vung.Count
    MsgBox i
End Sub

Đổi thành thế này lại OK
PHP:
Sub loc()
  Dim Vung
        Set Vung = Range([A1], [A65000].End(xlUp))
  i = Count(Vung)
    MsgBox i
   End Sub
lại được.

(Bởi tôi cứ hay nhầm cách sử dụng Count và Ubound), do IQ của tôi tiếp thu chậm quá, xin mọi người giảng giải cho.
Như nhiều lần đã đề cập, SET dùng để khởi tạo 1 biến thuộc Object...
Object (hay đối tượng) là những biến như: Hình vẽ, các đối tượng thuộc thanh Forms, Workbook, Worksheet... vân vân...
Vì đã khai báo ở đầu code Dim Vung As Range nên đương nhiên Vung phải là Object ---> Thế thì nếu không có SET "nó" không chịu (quy định thế thôi)
---------------
COUNT và Ubound hoàn toàn khác nhau.
Count thường là thuộc tính của Range (đếm số cell) trong khi Ubound không phải dùng để đếm. Ubound là 1 số dùng để xác định chỉ số phần tử cuối cùng của 1 mảng
Ví dụ:
Dim Arr(1 to 5)
thì UBound(Arr) sẽ = 5 ---> chính là chỉ số thứ tự cuối cùng của mảng Arr ---> Trùng hợp, số phần tử của Arr cũng = 5
Một ví dụ khác
Dim Arr(5)
Thì UBound(Arr) sẽ = 5 ---> chính là chỉ số thứ tự cuối cùng của mảng Arr nhưng tổng số phần tử của Arr lại = 6 (vì chỉ số đầu tiên của Arr trong trường hợp này bắt đầu bằng 0 chứ không bằng 1 như ví dụ trên)
Ngược với Ubound là Lbound, nó dùng để xác định chỉ số thứ tự đầu tiên của mảng
-----------
So sánh 2 "em" Count và Ubound này có thể mường tượng như khi so sánh hàm ROW và ROWS ấy (ROW là chỉ số dòng trong khi ROWS là tổng số dòng)
 
Lần chỉnh sửa cuối:
Upvote 0
Tức là khi khai báo biến thằng nào chắc chắn là mảng thì khai báo VD: Dim Dic As Range, nếu biết chắc chắn là Long thì khai báo long, còn các cái khác cứ để chung chung không nói gì thì nó tự hiểu là Variant hả thày?
 
Upvote 0
Đúng cả, trừ cái này
Tức là khi khai báo biến thằng nào chắc chắn là mảng thì khai báo VD: Dim Dic As Range
Chắc chắc là mảng thì phải Dim Dic() hoặc Dim Dic hoặc Dim Dic as Variant
Còn nếu chắc chắn là Range thì mới.. As Range chứ
 
Upvote 0
Tức là khi khai báo biến thằng nào chắc chắn là mảng thì khai báo VD: Dim Dic As Range, nếu biết chắc chắn là Long thì khai báo long, còn các cái khác cứ để chung chung không nói gì thì nó tự hiểu là Variant hả thày?
Không đúng
.....thằng nào chắc chắn là mảng thì khai báo VD: Dim Dic As Range...
range không phải là biến kiểu mảng mà là một trong các kiểu biến Object
.....còn các cái khác cứ để chung chung không nói gì thì nó tự hiểu là Variant......
cứ để thế thì biến là empty chứ không phải Variant
Khi bạn khai báo Dim trungvdb thì biến trungvdb là Empty
Nếu bạn gán trungvdb =1 thì trungvdb là Integer
Nếu bạn gán trungvdb ="Concogia" thì trungvdb là String
Nếu bạn gán trungvdb =Range("A1:A100") thì trungvdb là Variant
Nếu bạn gán Set trungvdb =Range("A1:A100") thì trungvdb là Range
Híc
 
Upvote 0
Web KT
Back
Top Bottom