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,599
Được thích
2,908
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ị
 
Nhờ mọi người xem giúp em File này. Mục đích của em là loại bỏ các giá trị trùng nhau đồng thời sắp xếp lại các phần tử của cột theo thứ tự tăng dần. Em không hiểu sao lại bị báo lỗi ở câu lệnh Redim Preserve ...

Cảm ơn mọi người !
 

File đính kèm

  • sắp xếp.xls
    36 KB · Đọc: 21
Upvote 0
Nhờ mọi người xem giúp em File này. Mục đích của em là loại bỏ các giá trị trùng nhau đồng thời sắp xếp lại các phần tử của cột theo thứ tự tăng dần. Em không hiểu sao lại bị báo lỗi ở câu lệnh Redim Preserve ...

Cảm ơn mọi người !
Hiểu nôm na là thế này bạn:

Code của bạn
Mã:
ReDim Preserve mang(1 To k, 1 To 1)
Tức là tăng số "Hàng"

Nhưng

Redim Preserve chỉ cho phép tăng số "Cột"

Gpe nói nhiều về cái này, bạn tìm hiểu thêm nhé
 
Upvote 0
Hiểu nôm na là thế này bạn:

Code của bạn
Mã:
ReDim Preserve mang(1 To k, 1 To 1)
Tức là tăng số "Hàng"

Nhưng

Redim Preserve chỉ cho phép tăng số "Cột"


Gpe nói nhiều về cái này, bạn tìm hiểu thêm nhé
Em đã đổi lại thành Redim theo chiều cột rồi mà vẫn báo lỗi vậy ah
 
Upvote 0
Nhưng với bài toán của chàng thì làm gì mà phức tạp vậy

1. Viết 1 Dic lọc duy nhất bình thường, dán kết quả xuống sheet
2. Sau đó dùng excel mà Sort từ bé tới lớn là được kết quả như ý...

Đừng si nghĩ chi cho mệt óc nha em!

Vâng anh, tại em đang thử cách này để làm 1 bài toán khác í mà ...
 
Upvote 0
Vâng anh, tại em đang thử cách này để làm 1 bài toán khác í mà ...

Thử không xài "muối" mà xài "mắm" xem sao.
PHP:
Public Sub GPE()
Dim Arr, Tmp, dArr(), I As Long, Rws As Long, K As Long
Arr = Range("A1", Range("A1").End(xlDown)).Value
Rws = UBound(Arr)
ReDim Tmp(Rws)
For I = 1 To UBound(Arr)
    If Arr(I, 1) > Rws Then
        Rws = Arr(I, 1)
        ReDim Preserve Tmp(Rws)
    End If
        Tmp(Arr(I, 1)) = Arr(I, 1)
Next I
ReDim dArr(1 To Rws + 1, 1 To 1)
For I = 0 To Rws
    If Tmp(I) <> "" Then
        K = K + 1
        dArr(K, 1) = Tmp(I)
    End If
Next I
[R2].Resize(K) = dArr
End Sub
 
Upvote 0
Cảm ơn mọi người đã hỗ trợ. Em kết hợp cả 2 cách của anh hpkhuong với anh dhn46 lại thì ra được kết quả rồi

Cảm ơn thầy BaTe đã khuyến mãi thêm 1 cách làm nữa.
 
Upvote 0
Gởi các bạn bài tập sử dụng mảng để tính subtotal cho các đối tượng, bài này tôi chỉ đưa ra ý tưởng là chèn thêm dòng total dưới các vị trí trùng nhau, các bạn có thể phát triển nó để có thể tính tổng con, đếm, hay tính trung bình của những nhóm, cái này tôi sử dụng mảng để chèn, và có sử dụng kỹ thuật chương trình con để làm
(code của tôi không có bẫy bất cứ lỗi gì? đây chỉ là ý tưởng nếu ai quan tâm thì có thể phát triển nhiều hướng cho mình, vì sử dụng chèn dòng trong excel với số lượng nhiều thì rất chậm)
Mã:
' Sub chen tung dong
Sub CHENDONG(VT_Chen As Long, Arr_D(), Sodong As Long)
Dim I As Long
   For I = Sodong To VT_Chen Step -1
     Arr_D(I, 1) = Arr_D(I - 1, 1)
   Next
   Arr_D(VT_Chen, 1) = "Total"
End Sub

Mã:
Sub Main()
Dim Arr_D(1 To 10000, 1 To 2)
Dim Arr_N()
Dim I As Long
Dim dongcuoi As Long
Dim VT_Chen As Long
Dim Sodong As Long


dongcuoi = Sheet1.Range("A10000").End(xlUp).Row
Arr_N = Sheet1.Range("A1:A" & dongcuoi + 1)
Sodong = UBound(Arr_N, 1)
'duyet tu dau den cuoi mang nguon gan vao mang dich
For I = 1 To UBound(Arr_N, 1)
  Arr_D(I, 1) = Arr_N(I, 1)
Next


' Kiem tra dieu kien tung phan tu neu Dung dieu kien thi goi sub chen dong
For I = UBound(Arr_N, 1) To 2 Step -1
  If (Arr_N(I, 1) <> Arr_N(I - 1, 1)) Then
     VT_Chen = I
     Sodong = Sodong + 1
     Call CHENDONG(VT_Chen, Arr_D, Sodong)
  End If
 Next


Sheet1.Range("B1:B10000").Clear
Sheet1.Range("B1").Resize(Sodong, 1) = Arr_D
End Sub
 

File đính kèm

  • subtotal.xlsb
    17 KB · Đọc: 34
Upvote 0
Gởi các bạn bài tập sử dụng mảng để tính subtotal cho các đối tượng, bài này tôi chỉ đưa ra ý tưởng là chèn thêm dòng total dưới các vị trí trùng nhau, các bạn có thể phát triển nó để có thể tính tổng con, đếm, hay tính trung bình của những nhóm, cái này tôi sử dụng mảng để chèn, và có sử dụng kỹ thuật chương trình con để làm
(code của tôi không có bẫy bất cứ lỗi gì? đây chỉ là ý tưởng nếu ai quan tâm thì có thể phát triển nhiều hướng cho mình, vì sử dụng chèn dòng trong excel với số lượng nhiều thì rất chậm)
Mã:
' Sub chen tung dong
Sub CHENDONG(VT_Chen As Long, Arr_D(), Sodong As Long)
Dim I As Long
   For I = Sodong To VT_Chen Step -1
     Arr_D(I, 1) = Arr_D(I - 1, 1)
   Next
   Arr_D(VT_Chen, 1) = "Total"
End Sub

Mã:
Sub Main()
Dim Arr_D(1 To 10000, 1 To 2)
Dim Arr_N()
Dim I As Long
Dim dongcuoi As Long
Dim VT_Chen As Long
Dim Sodong As Long


dongcuoi = Sheet1.Range("A10000").End(xlUp).Row
Arr_N = Sheet1.Range("A1:A" & dongcuoi + 1)
Sodong = UBound(Arr_N, 1)
'duyet tu dau den cuoi mang nguon gan vao mang dich
For I = 1 To UBound(Arr_N, 1)
  Arr_D(I, 1) = Arr_N(I, 1)
Next


' Kiem tra dieu kien tung phan tu neu Dung dieu kien thi goi sub chen dong
For I = UBound(Arr_N, 1) To 2 Step -1
  If (Arr_N(I, 1) <> Arr_N(I - 1, 1)) Then
     VT_Chen = I
     Sodong = Sodong + 1
     Call CHENDONG(VT_Chen, Arr_D, Sodong)
  End If
 Next


Sheet1.Range("B1:B10000").Clear
Sheet1.Range("B1").Resize(Sodong, 1) = Arr_D
End Sub

người viết ở trên quan tâm tới trường hợp số lượng lớn dòng dữ liệu trong excel , nhưng lại chọn cách viết code rất "hao xăng" để giải bài toán này ?
Tôi sẽ đi phân tích ý nghĩa đoạn ở trên . Giải thuật
Cứ gặp hiện tượng giá trị mảng của dòng hiện tại khác với dòng ngay trước nó
Mã:
If (Arr_N(I, 1) <> Arr_N(I - 1, 1)) Then
thì số dòng tổng cộng trong mảng kết quả phải điều chỉnh tăng 1 ( vì chèn thêm dòng "total")
và tiến hành duyệt mảng kết quả , sửa lại ghi đè tất cả các giá trị đã gán trước đó .
Vậy với mỗi lần xảy ra
Mã:
If (Arr_N(I, 1) <> Arr_N(I - 1, 1)) Then
lại tiến hành ghi đè tất cả các giá trị đã gán trước đó ?

Mã:
For I = Sodong To VT_Chen Step -1
     Arr_D(I, 1) = Arr_D(I - 1, 1)
   Next
như thế càng tiến gần về đích 2
Mã:
For I = UBound(Arr_N, 1) To 2 Step -1

thì số giá trị phải ghi đè càng lớn , điều này là đáng kể đối với excel dữ liệu lớn .
Nhưng tùy mỗi người nhận thức , có người cho rằng với bài này phải dùng kỹ thuật chia sub con mới là đỉnh cao của lập trình thì cũng được , tự do mà .
Với tôi thì theo đúng đề bài này tôi chỉ sử dụng 1 sub theo tinh thần duyệt mảng

Mã:
Public Sub hello()
Dim arr, dArr(1 To 100000, 1 To 1), r As Long, k As Long, ub As Long
arr = Sheet1.Range("A1:A" & Sheet1.[A10000].End(xlUp).Row).Value
ub = UBound(arr)
For r = 1 To ub Step 1
    k = k + 1
    dArr(k, 1) = arr(r, 1)
    If arr(r, 1) <> arr(WorksheetFunction.Min(r + 1, ub), 1) Or r = ub Then
        k = k + 1
        dArr(k, 1) = "total"
    End If
Next
Sheet1.Range("B1:B10000").Clear
Sheet1.Range("B1").Resize(k, 1) = dArr
End Sub
 
Upvote 0
người viết ở trên quan tâm tới trường hợp số lượng lớn dòng dữ liệu trong excel , nhưng lại chọn cách viết code rất "hao xăng" để giải bài toán này ?
Tôi sẽ đi phân tích ý nghĩa đoạn ở trên . Giải thuật
Cứ gặp hiện tượng giá trị mảng của dòng hiện tại khác với dòng ngay trước nó
Mã:
If (Arr_N(I, 1) <> Arr_N(I - 1, 1)) Then
thì số dòng tổng cộng trong mảng kết quả phải điều chỉnh tăng 1 ( vì chèn thêm dòng "total")
và tiến hành duyệt mảng kết quả , sửa lại ghi đè tất cả các giá trị đã gán trước đó .
Vậy với mỗi lần xảy ra
Mã:
If (Arr_N(I, 1) <> Arr_N(I - 1, 1)) Then
lại tiến hành ghi đè tất cả các giá trị đã gán trước đó ?

Mã:
For I = Sodong To VT_Chen Step -1
     Arr_D(I, 1) = Arr_D(I - 1, 1)
   Next
như thế càng tiến gần về đích 2
Mã:
For I = UBound(Arr_N, 1) To 2 Step -1

thì số giá trị phải ghi đè càng lớn , điều này là đáng kể đối với excel dữ liệu lớn .
Nhưng tùy mỗi người nhận thức , có người cho rằng với bài này phải dùng kỹ thuật chia sub con mới là đỉnh cao của lập trình thì cũng được , tự do mà .
Với tôi thì theo đúng đề bài này tôi chỉ sử dụng 1 sub theo tinh thần duyệt mảng

Mã:
Public Sub hello()
Dim arr, dArr(1 To 100000, 1 To 1), r As Long, k As Long, ub As Long
arr = Sheet1.Range("A1:A" & Sheet1.[A10000].End(xlUp).Row).Value
ub = UBound(arr)
For r = 1 To ub Step 1
    k = k + 1
    dArr(k, 1) = arr(r, 1)
    If arr(r, 1) <> arr(WorksheetFunction.Min(r + 1, ub), 1) Or r = ub Then
        k = k + 1
        dArr(k, 1) = "total"
    End If
Next
Sheet1.Range("B1:B10000").Clear
Sheet1.Range("B1").Resize(k, 1) = dArr
End Sub
nếu không lại tiến hành ghi đè tất cả các giá trị đã gán trước đó ? Thì bạn cứ cho 1 giải thuật chèn dòng đi, theo sách vở thì tôi chỉ biết chèn dòng thì như vậy thôi, chả biết hơn nữa đâu(trong code của bạn thì bạn có lợi dụng hàm MIN trong excel, mà cái hàm đó suy cho cùng thì cũng dùng vòng lặp duyệt từ bên trong mà thôi). Ý thức tôi kém nên tôi mới biết tới là chia nhỏ chương trình con là đỉnh cao trong lặp trình thôi, còn những ý thức cao siêu thì tôi không biết
tôi chỉ biết là chương trình chính chỉ nên gọi các thủ tục và hàm, để người ta dễ hình dung chương trình làm gì và dễ kiểm soát lỗi thôi bạn
 
Lần chỉnh sửa cuối:
Upvote 0
Xin chào đại gia đình GPE, trước tiên cho em cảm ơn đến tất cả các thành viên về các bài viết của anh chị đã giúp ích được rất nhiều người kể cả em.
em có 1 vấn đề này thắc mắc mà không biết giải quyết như thế nào? em có đọc bài anh lê văn duyệt về mảng nhưng chưa thực hành được
vấn đề 1:
em có đoạn code
Mã:
Dim Arr()
Arr = Array(Array(1, 2, 3))
dĩ nhiên Arr là mảng một chiều

nhưng lời của anh Lê văn duyệt
[FONT=&amp]Nếu dùng từ khóa Array, chỉ trả về mảng chỉ có một chiều nếu muốn trả về một mảng hai chiều chúng ta phải dùng [/FONT]Array(Array(…))

em muốn gán mảng 2 chiều theo yêu cầu này mà không được?
Mã:
Dim Arr()
Dim AB As Long
Arr = Array(Array(1, 2, 3), Array(4, 5, 6), Array(7, 8, 9), Array(10, 11, 12))
MsgBox Arr(1)(1)

em chỉ làm được như vậy thôi, mà như vậy thì nó là mảng một chiều trong mảng một chiều?
có cách nào gán mảng 2 chiều trực tiếp bằng array?
cũng là vấn đề này em muốn khai báo mảng tường minh được không
ví dụ
Arr(1 to 10) đây là mảng một chiều
còn mảng 1 chiều trong mảng 1 chiều khai báo sao?

Vấn đề 2:
khai báo mảng trong mảng, thao tác mảng trong mảng...
xin chân thành cảm ơn

 
Upvote 0
Xin chào đại gia đình GPE, trước tiên cho em cảm ơn đến tất cả các thành viên về các bài viết của anh chị đã giúp ích được rất nhiều người kể cả em.
em có 1 vấn đề này thắc mắc mà không biết giải quyết như thế nào? em có đọc bài anh lê văn duyệt về mảng nhưng chưa thực hành được
vấn đề 1:
em có đoạn code
Mã:
Dim Arr()
Arr = Array(Array(1, 2, 3))
dĩ nhiên Arr là mảng một chiều

nhưng lời của anh Lê văn duyệt
[FONT=&amp]Nếu dùng từ khóa Array, chỉ trả về mảng chỉ có một chiều nếu muốn trả về một mảng hai chiều chúng ta phải dùng [/FONT]Array(Array(…))

em muốn gán mảng 2 chiều theo yêu cầu này mà không được?
Mã:
Dim Arr()
Dim AB As Long
Arr = Array(Array(1, 2, 3), Array(4, 5, 6), Array(7, 8, 9), Array(10, 11, 12))
MsgBox Arr(1)(1)

em chỉ làm được như vậy thôi, mà như vậy thì nó là mảng một chiều trong mảng một chiều?
có cách nào gán mảng 2 chiều trực tiếp bằng array?
cũng là vấn đề này em muốn khai báo mảng tường minh được không
ví dụ
Arr(1 to 10) đây là mảng một chiều
còn mảng 1 chiều trong mảng 1 chiều khai báo sao?

Vấn đề 2:
khai báo mảng trong mảng, thao tác mảng trong mảng...
xin chân thành cảm ơn

Vấn đề 1:

Đầu tiên, ta phải hiểu rằng Array là một hàm mảng một chiều.

Array Function

Returns a Variant containing an array.

Thứ 2, với kiểu triển khai như thế này:

Array(Array(1, 2, 3), Array(4, 5, 6), Array(7, 8, 9), Array(10, 11, 12))

được gọi là "mảng trong mảng", với mảng một chiều "mẹ" chứa các phần tử là các mảng một chiều "con" (có thể chứa thêm cháu chắt gì nữa cũng được).

Thứ 3, đã là hàm mảng 1 chiều thì không thể chuyển hàm Array thành mảng 2 chiều được. Vậy nên muốn có mảng 2 chiều, hoặc nhiều hơn thì ta phải khai báo.

Ví dụ:

Mã:
Dim Arr2D(1 To 5, 1 To 2)

Ta thấy rằng chiều "hàng" nó có 5 hàng, và chiều "cột" nó có 2 cột. Với mỗi hàng nó sẽ chứa 2 phần tử của cột, từ đó bạn sẽ hiểu tính chất của nó mà làm việc với mảng 2 chiều.

Khai báo mảng trong mảng 1 chiều ta chỉ khai báo 2 mảng, một mảng "mẹ" và một mảng "con" (nếu mảng con có số phần tử là bằng nhau).

Mã:
Dim Arr1D_Mother(1 To 10)
Dim Arr1D_Daugter(1 To 5)

Khi triển khai bạn cứ tạo mảng con trước sau đó "gán" nó thành một phần tử của mảng "mẹ" và cứ thế cho đến hết 10 phần tử.

Vấn đề 2:

Như đã nói ở phần màu xanh, dưới đây là code để chứng minh điều đó:

Mã:
Sub Test()
    Dim Arr1D_Mother(1 To 10)
    Dim Arr1D_Daugter(1 To 5)
    Dim c As Long, r As Long
    For r = 1 To 10
        For c = 1 To 5
            Arr1D_Daugter(c) = r & c
        Next
        Arr1D_Mother(r) = Arr1D_Daugter
    Next
    MsgBox Arr1D_Mother(3)(4)
End Sub

Như vậy, MsgBox sẽ cho ra kết quả là 34 (3 và 4) vì đó là số ghép giữa phần tử thứ 3 của mảng mẹ với phần tử thứ 4 của mảng con.

Với những gì tôi nêu trên, hy vọng bạn hiểu thêm về chúng.
 
Upvote 0
Cảm ơn anh nghĩa nhiều, vấn đề này em đã tham khảo trong topic này trang 17 rồi. Em cũng hiểu và vận dụng được

Sub Test()
Dim Arr1D_Mother(1 To 10)
Dim Arr1D_Daugter(1 To 5)
Dim c As Long, r As Long
For r = 1 To 10
For c = 1 To 5
Arr1D_Daugter(c) = r & c
Next
Arr1D_Mother(r) = Arr1D_Daugter
Next
MsgBox Arr1D_Mother(3)(4)
End Sub
ý em muốn biết là mình có khai báo tường minh mảng con trong mảng mẹ hay không thôi? và cách truy xuất và gán giá trị ?
và vấn đề thứ nhất của em Array đúng là mảng một chiều, nhưng em có đọc bài anh Lê Văn Duyệt có nói là làm được nên em muốn tò mò xem sao thôi.
Nguyên văn bài của anh Duyệt
Nếu dùng từ khóa Array, chỉ trả về mảng chỉ có một chiều nếu muốn trả về một mảng hai chiều chúng ta phải dùng
Array(Array(…))

cảm ơn anh Nghĩa đẹp trai đã giúp đỡ nhiệt tình
 
Lần chỉnh sửa cuối:
Upvote 0
em muốn gán mảng 2 chiều theo yêu cầu này mà không được?
Mã:
Dim Arr()
Dim AB As Long
Arr = Array(Array(1, 2, 3), Array(4, 5, 6), Array(7, 8, 9), Array(10, 11, 12))
MsgBox Arr(1)(1)

em chỉ làm được như vậy thôi, mà như vậy thì nó là mảng một chiều trong mảng một chiều?
có cách nào gán mảng 2 chiều trực tiếp bằng array?

Tôi thường làm thế này:
Mã:
Sub Test2()
  Dim arr
  arr = [{1,2,3;4,5,6;7,8,9;10,11,12}]
  Range("A1:C4").Value = arr
End Sub
Thử xem.. hên thì được còn xui thì.. thôi vậy!
 
Upvote 0
Tôi thường làm thế này:
Mã:
Sub Test2()
  Dim arr
  arr = [{1,2,3;4,5,6;7,8,9;10,11,12}]
  Range("A1:C4").Value = arr
End Sub
Thử xem.. hên thì được còn xui thì.. thôi vậy!
cảm ơn anh ndu, xem như đã giải quyết được 1 yêu cầu rồi, cảm ơn anh ndu nhiều, tuy rằng những cái vấn đề này nó không quan trọng lắm nhưng mà em muốn biết tường tận để thỏa lòng thỏa dạ
 
Lần chỉnh sửa cuối:
Upvote 0
ý em muốn biết là mình có khai báo tường minh mảng con trong mảng mẹ hay không thôi? và cách truy xuất và gán giá trị ?
và vấn đề thứ nhất của em Array đúng là mảng một chiều, nhưng em có đọc bài anh Lê Văn Duyệt có nói là làm được nên em muốn tò mò xem sao thôi.
Nguyên văn bài của anh Duyệt
Nếu dùng từ khóa Array, chỉ trả về mảng chỉ có một chiều nếu muốn trả về một mảng hai chiều chúng ta phải dùng
Array(Array(…))
cảm ơn anh Nghĩa đẹp trai đã giúp đỡ nhiệt tình

Tôi không nghĩ với cách màu đỏ lại trở thành mảng 2 chiều được!
 
Upvote 0
Dạ cái đó là hên suôi, em cũng thử chưa ra, nhưng đọc bài của anh Duyệt thấy như vậy nên tò mò thôi anh, tò mò hoài không ra nên hỏi xem có đáp án nào không.
Vậy bạn đọc nó ở đâu? Bạn cho cái link đến đó để tôi nghiên cứu xem sao!
 
Upvote 0
Web KT

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

Back
Top Bottom