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

snow25

Thành viên gắn bó
Tham gia ngày
24 Tháng bảy 2018
Bài viết
2,220
Được thích
1,996
Điểm
360
Hi cảm ơn snow25 đã hỗ trợ.
Mục đích OT chỉ là tìm hiểu thêm về "ReDim Preserve" làm sao để thay đổi kích thước mảng vừa đủ ứng với số phần tử thỏa mãn cần xuất ra ạ. :)


Dạ, Bác biết link nào bàn chi tiết cho những người "ngu lâu, chậm hiểu" như con có khả năng tiếp thu được chút ít thì Bác chỉ cho con với ạ :D
Bạn thử cái này.
Mã:
Sub TongHop2()
    Dim Data(), arr(), i As Long, TenKh As String, j As Long, k As Long
    Sheet2.Range("H2").Resize(1000, 7).ClearContents
    Data = Sheet2.Range("A2:F15").Value
        For i = 1 To UBound(Data)
            If Data(i, 1) = "Tên KH" Then TenKh = Data(i, 2)
            If IsDate(Data(i, 1)) Then
                k = k + 1
                ReDim Preserve arr(1 To 7, 1 To k)
                arr(1, k) = TenKh
                For j = 1 To 6
                    arr(j + 1, k) = Data(i, j)
                Next j
            End If
        Next i
        arr = chuyenmang(arr)
    If k Then
        Sheet2.Range("H2").Resize(k, 7).Value = arr
    End If
End Sub
Function chuyenmang(mang As Variant)
        Dim arr, i As Long, j As Long
        ReDim arr(1 To UBound(mang, 2), 1 To UBound(mang, 1))
             For i = 1 To UBound(mang, 1)
                 For j = 1 To UBound(mang, 2)
                     arr(j, i) = mang(i, j)
                 Next j
             Next i
             chuyenmang = arr
End Function
 

leonguyenz

╠╗╦══╦╔╣
Thành viên BQT
Moderator
Tham gia ngày
2 Tháng tám 2010
Bài viết
4,349
Được thích
7,628
Điểm
610
Nơi ở
Bình Dương
Hi cảm ơn snow25 đã hỗ trợ.
Mục đích OT chỉ là tìm hiểu thêm về "ReDim Preserve" làm sao để thay đổi kích thước mảng vừa đủ ứng với số phần tử thỏa mãn cần xuất ra ạ. :)


Dạ, Bác biết link nào bàn chi tiết cho những người "ngu lâu, chậm hiểu" như con có khả năng tiếp thu được chút ít thì Bác chỉ cho con với ạ :D
Mỗi lần Redim mảng sẽ làm chậm tốc độ thực thi, đưa vào vòng lặp để Redim Preserve lại càng thêm chậm.
Như vậy có cần thiết Redim Preserve hay không? Nếu cần thiết thì cứ tính toán hết đi rồi Redim Preserve 1 lần.
 

Nguyễn Hoàng Oanh Thơ

Thành viên tích cực
Tham gia ngày
5 Tháng mười một 2015
Bài viết
1,023
Được thích
393
Điểm
235
Nơi ở
Hà Nội
Bạn thử cái này.
Mã:
Sub TongHop2()
    Dim Data(), arr(), i As Long, TenKh As String, j As Long, k As Long
    Sheet2.Range("H2").Resize(1000, 7).ClearContents
    Data = Sheet2.Range("A2:F15").Value
        For i = 1 To UBound(Data)
            If Data(i, 1) = "Tên KH" Then TenKh = Data(i, 2)
            If IsDate(Data(i, 1)) Then
                k = k + 1
                ReDim Preserve arr(1 To 7, 1 To k)
                arr(1, k) = TenKh
                For j = 1 To 6
                    arr(j + 1, k) = Data(i, j)
                Next j
            End If
        Next i
        arr = chuyenmang(arr)
    If k Then
        Sheet2.Range("H2").Resize(k, 7).Value = arr
    End If
End Sub
Function chuyenmang(mang As Variant)
        Dim arr, i As Long, j As Long
        ReDim arr(1 To UBound(mang, 2), 1 To UBound(mang, 1))
             For i = 1 To UBound(mang, 1)
                 For j = 1 To UBound(mang, 2)
                     arr(j, i) = mang(i, j)
                 Next j
             Next i
             chuyenmang = arr
End Function
Hihi, cảm ơn snow25 đã cho một cách tham khảo.

Mỗi lần Redim mảng sẽ làm chậm tốc độ thực thi, đưa vào vòng lặp để Redim Preserve lại càng thêm chậm.
Như vậy có cần thiết Redim Preserve hay không? Nếu cần thiết thì cứ tính toán hết đi rồi Redim Preserve 1 lần.
Dạ vâng Anh, OT cũng có nghĩ tốc độ có thể sẽ chậm hơn thật.. chỉ là tham khảo thêm về cách sử dụng Redim Preserve thôi ạ.
Nhưng xem chừng OT vẫn còn ngu ngơ lắm ạ :D
 

tueyennhi

Thành viên tích cực
Tham gia ngày
18 Tháng mười 2010
Bài viết
1,096
Được thích
89
Điểm
420
Tuổi
30
Cho em hỏi về mảng liên quan đến Dic. Em có đọc thấy Item có thể nhận kiểu dữ liệu là mảng. Vậy làm thế nào để add mảng làm item và khi muốn lấy giá trị một phần tử bất kì của mảng (item) đó thì em phải làm thế nào?
Ví dụ đây là đoạn code của em vậy add mảng tại ??? như thế nào mọi người chỉ giúp em được không?
PHP:
If Ws.Tab.Color = 10498160 Then
     BS = Ws.Range("AJ9", Ws.Range("AJ10000").End(xlUp)).Resize(, 3).Value
     For i = 1 To UBound(BS, 1)
          Tem = BS(i, 1)
          If Not Dic.exists(Tem) And Len(Tem) > 0 Then Dic.Add Tem, ???
     Next i
End If
 
Lần chỉnh sửa cuối:

snow25

Thành viên gắn bó
Tham gia ngày
24 Tháng bảy 2018
Bài viết
2,220
Được thích
1,996
Điểm
360
Cho em hỏi về mảng liên quan đến Dic. Em có đọc thấy Item có thể nhận kiểu dữ liệu là mảng. Vậy làm thế nào để add mảng làm item và khi muốn lấy giá trị một phần tử bất kì của mảng (item) đó thì em phải làm thế nào?
Ví dụ đây là đoạn code của em vậy add mảng tại ??? như thế nào mọi người chỉ giúp em được không?
PHP:
If Ws.Tab.Color = 10498160 Then
     BS = Ws.Range("AJ9", Ws.Range("AJ10000").End(xlUp)).Resize(, 3).Value
     For i = 1 To UBound(BS, 1)
          Tem = BS(i, 1)
          If Not Dic.exists(Tem) And Len(Tem) > 0 Then Dic.Add Tem, ???
     Next i
End If
Bạn gán mảng vào item như bình thường thôi.Còn lấy ra tùy theo bạn muốn lấy cả mảng ra hay từng vị trí của mảng cũng được.
Mã:
If Ws.Tab.Color = 10498160 Then
     BS = Ws.Range("AJ9", Ws.Range("AJ10000").End(xlUp)).Resize(, 3).Value
     For i = 1 To UBound(BS, 1)
          tem = BS(i, 1)
          If Not dic.exists(tem) And Len(tem) > 0 Then
             dic.Add tem, Array(1, 2, 3)
             MsgBox dic.Item(tem)(0)
             MsgBox dic.Item(tem)(1)
             MsgBox dic.Item(tem)(2)
         end if
     Next i
End If
 

tueyennhi

Thành viên tích cực
Tham gia ngày
18 Tháng mười 2010
Bài viết
1,096
Được thích
89
Điểm
420
Tuổi
30
Bạn gán mảng vào item như bình thường thôi.Còn lấy ra tùy theo bạn muốn lấy cả mảng ra hay từng vị trí của mảng cũng được.
Mã:
If Ws.Tab.Color = 10498160 Then
     BS = Ws.Range("AJ9", Ws.Range("AJ10000").End(xlUp)).Resize(, 3).Value
     For i = 1 To UBound(BS, 1)
          tem = BS(i, 1)
          If Not dic.exists(tem) And Len(tem) > 0 Then
             dic.Add tem, Array(1, 2, 3)
             MsgBox dic.Item(tem)(0)
             MsgBox dic.Item(tem)(1)
             MsgBox dic.Item(tem)(2)
         end if
     Next i
End If
Em muốn gán mảng BS tại vị trí i thì em cần làm như thế nào hả anh? Hay em cần viết thêm là
For j =1 to 3
Arr(i,j)= BS(i,j)
Phải không anh?
 

CHAOQUAY

Thành viên tiêu biểu
Tham gia ngày
24 Tháng tám 2018
Bài viết
730
Được thích
651
Điểm
360
Mỗi lần Redim mảng sẽ làm chậm tốc độ thực thi, đưa vào vòng lặp để Redim Preserve lại càng thêm chậm.
Như vậy có cần thiết Redim Preserve hay không? Nếu cần thiết thì cứ tính toán hết đi rồi Redim Preserve 1 lần.
Việc này có lẽ chưa hoàn toàn đúng. Nếu sau mỗi lần redim preserve mà kích thước mảng giảm, khối lượng tính sẽ giảm, có lẽ code sẽ nhanh hơn ban đầu.
Còn nếu preserve mà kích thước lại tăng thì bó tay.
 

VetMini

Gian hùng bàn phiếm (thành viên trôi nước)
Tham gia ngày
21 Tháng mười hai 2012
Bài viết
7,118
Được thích
8,373
Điểm
560
Việc này có lẽ chưa hoàn toàn đúng. Nếu sau mỗi lần redim preserve mà kích thước mảng giảm, khối lượng tính sẽ giảm, có lẽ code sẽ nhanh hơn ban đầu.
Còn nếu preserve mà kích thước lại tăng thì bó tay.
.
Nói như vậy là rất mơ hồ.

Về Redim Preserve tôi đã từng nói về cách hoạt động của nó rồi. Chịu khó tìm thớt ấy.
Đại khái:
1. Mảng là cấu trúc cổ đại của lập trình. Nó gần như luôn luôn được thể hiện bằng một vùng nhớ liên tục. Mục đích là để giúp tốc độ. Vì vậy tốc độ sẽ liên quan đến chiều hướng truy cập. Và VBA dùng mảng truy theo cột. (Có một bạn đã từng chứng minh duyệt mảng theo cột nhanh hơn theo dòng)
2. Redim Preserve chủ yếu chỉ là tạo một mảng khác rồi copy mảng cũ sang. Khi VBA thực hiện lệnh này thì tôi nghĩ rằng bên trong nó dùng mấy cái macro (macro này viết bằng ASM) để copy toàn cụm vùng nhớ, không ai dại gì copy từng đoạn hay từng phần tử.
3. Mấy cái macro (ASM) dùng để Dim/Redim mảng cũng được viết rất hiệu quả. Cho nên tốc độ tuy có bị ảnh hưởng nhưng không nhiều như ta tưởng tượng.
4. Túm lại thì xào mảng đi lại cũng nên quan tâm ở điểm làm nát (fragment) bộ nhớ. Nhưng với các hệ điều hành mới (Win7 trở đi) thì VBA sử dụng code gom bộ nhớ (dọn rác/garbage collection) rất hiệu quả.
 
Lần chỉnh sửa cuối:

tueyennhi

Thành viên tích cực
Tham gia ngày
18 Tháng mười 2010
Bài viết
1,096
Được thích
89
Điểm
420
Tuổi
30
Em muốn gán mảng BS tại vị trí i thì em cần làm như thế nào hả anh? Hay em cần viết thêm là
For j =1 to 3
Arr(i,j)= BS(i,j)
Phải không anh?
Bạn gán mảng vào item như bình thường thôi.Còn lấy ra tùy theo bạn muốn lấy cả mảng ra hay từng vị trí của mảng cũng được.
Mã:
If Ws.Tab.Color = 10498160 Then
     BS = Ws.Range("AJ9", Ws.Range("AJ10000").End(xlUp)).Resize(, 3).Value
     For i = 1 To UBound(BS, 1)
          tem = BS(i, 1)
          If Not dic.exists(tem) And Len(tem) > 0 Then
             dic.Add tem, Array(1, 2, 3)
             MsgBox dic.Item(tem)(0)
             MsgBox dic.Item(tem)(1)
             MsgBox dic.Item(tem)(2)
         end if
     Next i
End If
Em làm được rồi nhé. Cảm ơn anh!
PHP:
Private Sub BoSungCong()
Dim BS(), i As Long, Dic As Object, Tem As String
Dim Ws As Worksheet
Set Dic = CreateObject("Scripting.Dictionary")
    For Each Ws In Worksheets
        If Ws.Tab.Color = 10498160 Then
            BS = Ws.Range("AJ9", Ws.Range("AJ10000").End(xlUp)).Resize(, 3).Value
            For i = 1 To UBound(BS, 1)
                Tem = Cells(i + 8, 3)
                If Not IsEmpty(Tem) And Not Dic.exists(Tem) Then Dic.Add Tem, Array(BS(i, 1), BS(i, 2), BS(i, 3))
            Next i
        End If
    Next Ws
End Sub
 

CHAOQUAY

Thành viên tiêu biểu
Tham gia ngày
24 Tháng tám 2018
Bài viết
730
Được thích
651
Điểm
360
Nói như vậy là rất mơ hồ.
...
Có lẽ nếu khối lượng tính toán giảm đáng kể tài nguyên máy so với redim preserve thì việc này cũng nên thử.
Thực tế sử dụng, nếu redim preserve cho mảng 1 chiều trong vòng lặp thấy có vẻ tốt bác ạ. Cái này thấy giống như lệnh Remove trong dictionary khi dùng trong vòng lặp.
Em chỉ thực tế thôi bác ạ.
 

VetMini

Gian hùng bàn phiếm (thành viên trôi nước)
Tham gia ngày
21 Tháng mười hai 2012
Bài viết
7,118
Được thích
8,373
Điểm
560
Tôi thường dùng từ rất đúng ngữ cảnh và ngữ pháp. Nếu tôi cho rằng "sai" thì tôi đã dùng từ "sai".
Tôi dùng từ "rất mơ hồ" bởi vì tôi cho rằng nói như vậy là "mơ hồ":
Chỉ nói suông kích thước tăng/giảm như vậy chưa đủ. Ít nhất phải cho biết tại sao thêm 1 dòng/cột lại tốn tài nguyên hơn bớt 1 dòng/cột.
Ví dụ: (giải thích rằng) thêm cột thì VBA phải tạo vùng nhớ mới; bớt cột thì vẫn giữ vùng nhớ ấy, chỉ thu ngắn lại thôi.
Lưu ý: ví dụ cụ thể thôi, thực tế tôi không tin VBA làm vậy. Tôi biết các macro tạo vùng nhớ và copy vùng nhớ của hệ thống làm việc hiệu quả lắm. Điển hình là mỗi lần bạn dùng toán tử & để gộp chuỗi là VBA phải tạo vùng nhớ mới và copy qua. (*)

(*) Đối với chuỗi, tôi vẫn khuyên là nếu tránh dùng & thì lại hiệu quả hơn. Nhưng nếu không tránh được thì cũng không đến nổi tốn kém quá.
 

CHAOQUAY

Thành viên tiêu biểu
Tham gia ngày
24 Tháng tám 2018
Bài viết
730
Được thích
651
Điểm
360
Tôi thường dùng từ rất đúng ngữ cảnh và ngữ pháp. Nếu tôi cho rằng "sai" thì tôi đã dùng từ "sai".
Tôi dùng từ "rất mơ hồ" bởi vì tôi cho rằng nói như vậy là "mơ hồ":
Chỉ nói suông kích thước tăng/giảm như vậy chưa đủ. Ít nhất phải cho biết tại sao thêm 1 dòng/cột lại tốn tài nguyên hơn bớt 1 dòng/cột.
Ví dụ: (giải thích rằng) thêm cột thì VBA phải tạo vùng nhớ mới; bớt cột thì vẫn giữ vùng nhớ ấy, chỉ thu ngắn lại thôi.
Lưu ý: ví dụ cụ thể thôi, thực tế tôi không tin VBA làm vậy. Tôi biết các macro tạo vùng nhớ và copy vùng nhớ của hệ thống làm việc hiệu quả lắm. Điển hình là mỗi lần bạn dùng toán tử & để gộp chuỗi là VBA phải tạo vùng nhớ mới và copy qua. (*)

(*) Đối với chuỗi, tôi vẫn khuyên là nếu tránh dùng & thì lại hiệu quả hơn. Nhưng nếu không tránh được thì cũng không đến nổi tốn kém quá.
Nếu chỉ xét riêng việc redim preserve trong vòng lặp thì chắc là code sẽ chậm hơn khi không redim, nhưng thực tế, viêc quét qua mảng thường kèm theo các phép tính liên quan nên việc redim mảng trong một số trường hợp có thể làm giảm khối lượng tính đi kèm. Trong trường hợp này, nếu khối lượng công việc đi kèm là đáng kể thì có thể code sẽ nhanh hơn nếu không redim & ngược lại, tính toán kèm theo là không lớn thì code cũng sẽ vẫn chậm hơn khi không redim.
Việc đánh giá là mơ hồ chỗ này thì cũng hoàn toàn đồng ý với bác .
 

befaint

|||||||||||||
Tham gia ngày
6 Tháng một 2011
Bài viết
8,719
Được thích
9,989
Điểm
560

HuyDương07

Thành viên mới
Tham gia ngày
9 Tháng tư 2019
Bài viết
1
Được thích
0
Điểm
13
Tuổi
30
Chào mọi người trong group

hiện tại mình mới bắt đầu học VBA excel (mình bên logictics) muốn có vấn đề muốn hỏi mong các pro chỉ giúp :
1. autofillter : mình có 1 bang data , mình muốn tự lọc theo dự liệu paste 1 cột
+> phần điều kiện Criteria : cột dữ lieu muốn filter thành 1 chuỗi arr(....) =Criteria?
+> có cần xác định dòng cuối dự lieu cần lọc không? có thì xin chỉ giáo giúp
2> khi lọc được những dữ lieu mình muốn lọc :
+> Tìm được date >2/3 ( date = ((HSD -now())/HSD - NXS) và số lượng của những dữ lieu (mã hang) mà mình muốn lọc
 

Minh Tùng

Thành viên mới
Tham gia ngày
16 Tháng ba 2014
Bài viết
41
Được thích
8
Điểm
365
Vấn đề của em khá nhỏ nên em không lập topic mới ạ (nếu em đăng sai, nhờ BQT nhắc nhở để em đăng bài mới)

Em có biến LastRow để xác định dòng cuối
Em cần chọn nhiều vùng không liền nhau kết hợp LastRow để xác định dữ liệu mảng động để format trước khi thêm dữ liệu vào sheetform nhưng em chưa viết được code (như hình em cần chọn ô bắt đầu là B2:C & LastRow, E2 & LastRow, G2 & LastRow, I2:K & LastRow,....)

Mong anh/chị GPE giúp em ạ.
Em cám ơn nhiều!
 

File đính kèm

snow25

Thành viên gắn bó
Tham gia ngày
24 Tháng bảy 2018
Bài viết
2,220
Được thích
1,996
Điểm
360
Vấn đề của em khá nhỏ nên em không lập topic mới ạ (nếu em đăng sai, nhờ BQT nhắc nhở để em đăng bài mới)

Em có biến LastRow để xác định dòng cuối
Em cần chọn nhiều vùng không liền nhau kết hợp LastRow để xác định dữ liệu mảng động để format trước khi thêm dữ liệu vào sheetform nhưng em chưa viết được code (như hình em cần chọn ô bắt đầu là B2:C & LastRow, E2 & LastRow, G2 & LastRow, I2:K & LastRow,....)

Mong anh/chị GPE giúp em ạ.
Em cám ơn nhiều!
Bạn viết vậy là bị lỗi.Bạn nên tách cái nào là biến cái nào là ký tự ra chứ.Bạn viết thế kia nó không hiểu cái Lastrow là gì cả.
 

Minh Tùng

Thành viên mới
Tham gia ngày
16 Tháng ba 2014
Bài viết
41
Được thích
8
Điểm
365
Bạn viết vậy là bị lỗi.Bạn nên tách cái nào là biến cái nào là ký tự ra chứ.Bạn viết thế kia nó không hiểu cái Lastrow là gì cả.
Tại vì em viết để dể hình dung đó anh
Bình thường nếu 1 vùng thì em sẽ viết là:

With Sheet1.Range("B2:B" & LastRow)
Code trong đây....
End With

Nhưng em chọn nhiều vùng không liên tục kèm theo biến LastRow thì em chưa làm được ạ.
Anh giúp em thêm được không?
 
Top Bottom