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ị
 
Em mới test sơ qua, code của sư phụ không thể gõ trực tiếp trên bảng tính được. Nó toàn lỗi #VALUE!
Gõ kí rì trên bảng tính? Có phải gõ =resizeArr(A2:C21, 7) hông?
Lỗi value hiện ra ở vùng kết quả hả? Đúng rồi!

Code này làm theo yêu cầu bài 30, với 1 Function đầu vào là Array, đầu ra cũng Array, kèm theo 1 Sub lấy Array nguồn từ bảng tính đấy chứ?
Nếu muốn lấy Array nguồn trực tiếp từ bảng tính (nghĩa là đầu vào có thể là Range) thì phải viết khác chứ? Đâu cần Sub nữa?

Cũng dễ thôi, chỉ cần thêm vào 1 câu:

SArr = SourceArr

và sửa câu:

ArrKQ(iKQ, jKQ) = SourceArr(iR, iC)

thành

ArrKQ(iKQ, jKQ) = SArr(iR, iC)

và không cần sub siếc, sub siếc để khi nào không muốn dùng công thức trên bảng tính mới dùng đến.

Bây giờ có thể thoải mái gõ: =resizeArr(A2:C21, 7), Ctrl Shift Enter
Đồng thời có thể truy xuất = Index(resizeArr(A2:C21, 7), 3, 6)
Sub siếc để nguyên và vẫn có thể chạy như cũ.

À hiểu rồi: câu này:
Nếu kích thước mảng kết quả > kịch thước mảng cho trước thì những phần tử thừa sẽ cho = Blank
phải phối hợp với câu này mới hiểu: (cha mẹ ơi, hôm nay nói 1 câu, sang hôm sau mới nói tiếp 1 câu)
em muốn xây dựng hàm Resize Array này sao cho nó hoạt động y chang như Resize Property của VBA
Nghĩa là không sắp xếp dữ liệu lại gì cả! ArrKQ(i, j) = SArr(i, j) (câu này chắc sang năm mới nói!)

Thôi, coi như bài tập mới, mai làm!
Mà Resize(m, n) của VBA liên quan gì đến gõ trên sheet hè?
 

File đính kèm

  • ResizeArr-Range.rar
    11.2 KB · Đọc: 154
Lần chỉnh sửa cuối:
Upvote 0

Mà Resize(m, n) của VBA liên quan gì đến gõ trên sheet hè?
Đúng ra hàm này dùng trong VBA là chính, nhưng em vẫn muốn mọi thứ được mở rộng theo hướng tổng quát nhất: Có thể hoạt động với Range, có thể hoạt động với Array (kể cả Array do công thức trả về) và có thể gõ được trên sheet
Ẹc... Ẹc...
 
Upvote 0
Đúng ra hàm này dùng trong VBA là chính, nhưng em vẫn muốn mọi thứ được mở rộng theo hướng tổng quát nhất: Có thể hoạt động với Range, có thể hoạt động với Array (kể cả Array do công thức trả về) và có thể gõ được trên sheet
Ẹc... Ẹc...

Bài trên bài trên (ẹc, mới gộp 2 bài), đã sửa để có thể lấy Range từ bảng tính, và đã có thể quánh công thức xuống bảng tính rồi đó.

Còn nếu chỉ đơn thuần là Resize như VBA, thì càng dễ hơn, chỉ cần gán ArrKQ (i, j) = sArr(i, j), với
i chạy từ 1 đến min(số dòng ArrKQ, số dòng sArr)
j chạy từ 1 đến Min(số cột ArrKQ, số cột sArr)

2 vòng lặp, khỏi If iếc. Nhường lại cho nmhung49 làm. Khà khà.
 
Upvote 0
Bài trên bài trên (ẹc, mới gộp 2 bài), đã sửa để có thể lấy Range từ bảng tính, và đã có thể quánh công thức xuống bảng tính rồi đó.

Còn nếu chỉ đơn thuần là Resize như VBA, thì càng dễ hơn, chỉ cần gán ArrKQ (i, j) = sArr(i, j), với
i chạy từ 1 đến min(số dòng ArrKQ, số dòng sArr)
j chạy từ 1 đến Min(số cột ArrKQ, số cột sArr)

2 vòng lặp, khỏi If iếc. Nhường lại cho nmhung49 làm. Khà khà.
Nhưng cái này mới hay nè sư phụ:
Nếu kích thước mảng kết quả > kịch thước mảng cho trước thì những phần tử thừa sẽ cho = Blank
Tức: Yêu cầu số dòng, số cột của mảng kết quả là bao nhiêu thì ta cứ giữ nguyên, và số phần tử thừa nếu có sẽ cho = Blank (không phải là chuổi rổng)
 
Upvote 0
Bài trên bài trên (ẹc, mới gộp 2 bài), đã sửa để có thể lấy Range từ bảng tính, và đã có thể quánh công thức xuống bảng tính rồi đó.

Còn nếu chỉ đơn thuần là Resize như VBA, thì càng dễ hơn, chỉ cần gán ArrKQ (i, j) = sArr(i, j), với
i chạy từ 1 đến min(số dòng ArrKQ, số dòng sArr)
j chạy từ 1 đến Min(số cột ArrKQ, số cột sArr)

2 vòng lặp, khỏi If iếc. Nhường lại cho nmhung49 làm. Khà khà.
Dạ em đâu có khả năng tới đó đâu Thầy ơi. Em nghe rằng mảng luôn cho tốc độ thuộc dạng khủng nhất nên em thử với dữ liệu 800.000 dòng để so sánh dùng Filter lọc dữ liệu mình cần thì thấy nó chậm kinh khủng mà trong khi đó mảng làm việc với tốc độ chống mặt mà sao dữ liệu bị biến đổi thành số mà không còn là dạng text nữa. Mà sao em lọc rồi copy bị báo lỗi "Microsoft office excel cannot create or use the data range reference because it is too complex" Không biết máy em có bị gì không mong anh chị test giúp em Thanks. Em tìm trên mạng thì trang này nó nói rằng http://www.mrexcel.com/forum/showthread.php?t=550686
 

File đính kèm

  • Hocmang.rar
    1.9 MB · Đọc: 351
Upvote 0
Dạ em đâu có khả năng tới đó đâu Thầy ơi. Em nghe rằng mảng luôn cho tốc độ thuộc dạng khủng nhất nên em thử với dữ liệu 800.000 dòng để so sánh dùng Filter lọc dữ liệu mình cần thì thấy nó chậm kinh khủng mà trong khi đó mảng làm việc với tốc độ chống mặt mà sao dữ liệu bị biến đổi thành số mà không còn là dạng text nữa
Code của bạn chưa phải là mảng. Đoạn này If Cells(li, 1).Value = "111250000125" Then vẫn xem như chưa "thoát ly" khỏi Range đâu (vì phải dựa vào Cells(li, 1) ). Vì thế tốc độ vẫn chậm
Tôi sửa lại như sau:
PHP:
Sub hocmang()
  Dim Arr() As String, sArray, li As Long, lj As Long
  sArray = Range("A1:A808945").Value
  ReDim Arr(1 To UBound(sArray, 1), 1 To UBound(sArray, 2))
  For li = 1 To UBound(sArray, 1)
    If sArray(li, 1) = "111250000125" Then
      lj = lj + 1
      Arr(lj, 1) = sArray(li, 1)
    End If
  Next li
  Range("E1").Resize(lj).Value = Arr
End Sub
- Thứ nhất: Không cần Option Base 1 gì cả, khai báo trực tiếp rằng ReDim Arr(1 To UBound(sArray, 1), 1 To UBound(sArray, 2))
- Thứ hai: Dim Arr() As String sẽ bảo đảm kết quả luôn là chuổi
- Thứ ba: Chổ này arr(UBound(sarr, 1), LBound(sarr, 1)) xem bộ không chuẩn (phải giống cái trên mới đúng)
Thử lại code tôi vừa đưa ở trên xem tốc độ thế nào
---------------------------------------------------------------------------------
Mà sao em lọc rồi copy bị báo lỗi "Microsoft office excel cannot create or use the data range reference because it is too complex" Không biết máy em có bị gì không mong anh chị test giúp em Thanks. Em tìm trên mạng thì trang này nó nói rằng http://www.mrexcel.com/forum/showthread.php?t=550686
Không biết báo lỗi copy với dữ liệu lọc bằng AutoFilter hay với code? ---> Đoán là báo lỗi khi copy dữ liệu sau AutoFilter! Điều này rất bình thường. SpecialCells sẽ có giới hạn với dữ liệu lớn ---> Nếu dùng Filter thì nên chuyển sang Advanced Filter, sẽ hết lỗi liền (vì không phải copy, lọc và đưa kết quả thẳng đến nơi ta cần luôn)
 
Lần chỉnh sửa cuối:
Upvote 0
Sao lại vầy:
ReDim arr(UBound(sarr, 1), LBound(sarr, 1))

Như vầy mới đúng chứ:
ReDim arr(UBound(sarr, 1), UBound(sarr, 2))
hoặc:
ReDim arr(UBound(sarr, 1), 1)

Mấy anh bên đó chưa học Array từ GPE nên xử lý 550.000 dòng nhanh nhất là 5 phút. Con nmhung49 xơi 800.000 dòng có 15 giây! (Máy cùn P4 của công ty đó nha, máy khác còn khủng thế nào nữa à.)

Nói tới dữ liệu lớn thì đừng nói gì công thức, AutoFilter cũng chết ngắc. Copy, Paste sau khi Filter cũng đi die, vì nó gồm quá nhiều mảnh nhỏ ghép lại, không phải 1 range liên tục.
Đã thí nghiệm:
Để nguyên không filter: copy, paste 800.000 cells vẫn được.
Sau khi filter: Copy bị báo lỗi như trên.
---------------------
Quên để ý vụ cells(li, 1).Value
Thay bằng sarr(li, 1)
Code chạy dưới 1 giây!
 
Lần chỉnh sửa cuối:
Upvote 0
Sub hocmang()
Dim arr(), sarr As Variant, li As Long, lj As Long
sarr = Range("a1:a808945").Value
ReDim arr(UBound(sarr, 1), LBound(sarr, 1))
Cái em này khai báo "trật lấc", sửa lại như Thầy ptm & ndu
Còn nếu biết chắc là 1 cột thì khai báo vầy cho gọn Redim arr(1 to UBound(sarr),1 to 1)
For li = 1 To UBound(arr, 1)
Nếu cho chạy theo dòng chỉ cần UBound(arr)
If Cells(li, 1).Value = "111250000125" Then
Cái em này cũng trật lấc, may mà dữ liệu của bạn ở cột A chứ ở cột khác là code này "tèo" chắc
lj = lj + 1
arr(lj, 1) = sarr(li, 1)
End If
Next li
[d1:d130000] = arr
Cái em này lý ra bạn viết
[d1].Resize(lj) = arr
End Sub
Nói chung, bài này viết đúng nó chạy cái.....roẹt là xong
Thân
 
Upvote 0
Sao lại vầy:
ReDim arr(UBound(sarr, 1), LBound(sarr, 1))

Như vầy mới đúng chứ:
ReDim arr(UBound(sarr, 1), UBound(sarr, 2))
hoặc:
ReDim arr(UBound(sarr, 1), 1)

Mấy anh bên đó chưa học Array từ GPE nên xử lý 550.000 dòng nhanh nhất là 5 phút. Con nmhung49 xơi 800.000 dòng có 15 giây! (Máy cùn P4 của công ty đó nha, máy khác còn khủng thế nào nữa à.)

Nói tới dữ liệu lớn thì đừng nói gì công thức, AutoFilter cũng chết ngắc. Copy, Paste sau khi Filter cũng đi die, vì nó gồm quá nhiều mảnh nhỏ ghép lại, không phải 1 range liên tục.
Đã thí nghiệm:
Để nguyên không filter: copy, paste 800.000 cells vẫn được.
Sau khi filter: Copy bị báo lỗi như trên.
Code chạy dưới 1 giây!
Đọc xong mấy bài các anh và Thầy em thấy code mình củ chuối thiệt chứ, cố gắng cải thiện để mà hỏi tiếp ặc...ặc...--=0--=0;;;;;;;;;;; mà sao em thấy diễn đàn mình không là thành viên của MVP của Microsoft hen thấy cũng lạ
Quên để ý vụ cells(li, 1).Value
Thay bằng sarr(li, 1)
Cho em hỏi sarr(li,1) nó hoạt động làm sao theo em nghĩ thì có phải nó duyệt qua từ giá trị trong mảng sarr = range("a1:a808945").value phải không ah!!
 
Lần chỉnh sửa cuối:
Upvote 0
Cho em hỏi sarr(li,1) nó hoạt động làm sao theo em nghĩ thì có phải nó duyệt qua từ giá trị trong mảng sarr = range("a1:a808945").value phải không ah!!

Bạn đã gán giá trị của range A1:A808945 vào mảng sarr trong câu:
sarr = Range("a1:a808945").Value

Vậy thì dò tìm, cũng dò tìm trên sarr, xét điều kiện, cũng xét điều kiện trên sarr, và truy xuất cũng truy xuất trên sarr.
Chứ mà cứ ngó ngó xuống cell thì ... gán sarr làm gì?

em nghĩ thì có phải nó duyệt qua từ giá trị trong mảng
Đúng, duyệt từng giá trị trong mảng, nhưng là mảng sarr, không phải range dưới sheet nữa. Có thế mới nhanh được chứ!
 
Upvote 0
Cho em hỏi có cách nào mình đổi tên sheet bằng cách dùng mảng không vậy các bạn. Thương ngày mình dùng code này để đổi tên mấy hôm nay tìm cách dùng mảng để đổi tên mà không tài nào biết được +-+-+-++-+-+-+. Mong các bạn giúp đỡ. Thanks
PHP:
Sub doiten()
Dim li As Long
For li = 1 To Sheets.Count
Sheets(li).Name = Cells(li, 1)
Next li
End Sub
 
Upvote 0
Cho em hỏi có cách nào mình đổi tên sheet bằng cách dùng mảng không vậy các bạn. Thương ngày mình dùng code này để đổi tên mấy hôm nay tìm cách dùng mảng để đổi tên mà không tài nào biết được +-+-+-++-+-+-+. Mong các bạn giúp đỡ. Thanks
PHP:
Sub doiten()
Dim li As Long
For li = 1 To Sheets.Count
Sheets(li).Name = Cells(li, 1)
Next li
End Sub
Có chăng là đổi mấy thằng Cells(li, 1) thành những phần tử trong mảng, nhưng tôi nghĩ chẳng ăn thua gì
Thử nghĩ xem người ta dùng 1 file nhiều nhất cũng chừng độ vài chục sheet ---> Tương ứng vòng lập duyệt bao nhiêu đó lần ---> Chẳng đáng bao nhiêu mà phải mất thời gian nghiên cứu (mà dù cố thì chắc cũng hổng có cách nào khác)
 
Upvote 0
Code Test1 trong bài #29 của ndu đọc Mảng ban đầu lấy số lẻ xong phân phối cho mảng kết quả theo thứ tự ưu tiên hàng ngang trước, dọc sau.

Xin giới thiệu code Test2, lấy số lẻ xong, của cột nào để nguyên cột đó:

PHP:
Sub Test2()
  Dim sArray, Arr(), i As Long, j As Long, iR1 As Long, iR2
  sArray = Range("A2:B11").Value
  ReDim Arr(1 To UBound(sArray), 1 To UBound(sArray, 2))
  For i = 1 To UBound(sArray, 1)
    For j = 1 To UBound(sArray, 2)
      If sArray(i, j) Mod 2 Then
        Arr(IIf(j = 1, iR1, iR2) + 1, j) = sArray(i, j)
        If j = 1 Then
            iR1 = iR1 + 1
        Else
            iR2 = iR2 + 1
        End If
     End If
    Next
  Next
  Range("E2:F11") = Arr
End Sub
Với đoạn code trên của Thấy Mỹ vậy cho em hỏi nếu dữ liệu nhiều hơn Range("A2:B11") cỡ chừng A2:AA100 thì mình không thể dùng
PHP:
If sArray(i, j) Mod 2 Then
        Arr(IIf(j = 1, iR1, iR2) + 1, j) = sArray(i, j)
        If j = 1 Then
            iR1 = iR1 + 1
        Else
            iR2 = iR2 + 1
        End If
     End If
được phải không ah, vậy cho cách nào linh hoạt hơn không các bạn, anh chị em mới học mảng nhiều khi câu hỏi ngô ghê xin đừng cười ạ. Thanks
 
Lần chỉnh sửa cuối:
Upvote 0
Với đoạn code trên của Thấy Mỹ vậy cho em hỏi nếu dữ liệu nhiều hơn Range("A2:B11") cỡ chừng A2:AA100 thì mình không thể dùng
PHP:
If sArray(i, j) Mod 2 Then
        Arr(IIf(j = 1, iR1, iR2) + 1, j) = sArray(i, j)
        If j = 1 Then
            iR1 = iR1 + 1
        Else
            iR2 = iR2 + 1
        End If
     End If
được phải không ah, vậy cho cách nào linh hoạt hơn không các bạn, anh chị em mới học mảng nhiều khi câu hỏi ngô ghê xin đừng cười ạ. Thanks
Vầy đi:
- Bước đầu tiếp cận với mảng 2 chiều, bạn cứ hãy tưởng tượng nó là Range đi ---> Cách truy xuất tương tự.
- Ngoài ra, nghĩ được cái gì thì cứ thí nghiệm rồi rút ra kết luận
 
Upvote 0
Với đoạn code trên của Thấy Mỹ vậy cho em hỏi nếu dữ liệu nhiều hơn Range("A2:B11") cỡ chừng A2:AA100 thì mình không thể dùng
PHP:
If sArray(i, j) Mod 2 Then
        Arr(IIf(j = 1, iR1, iR2) + 1, j) = sArray(i, j)
        If j = 1 Then
            iR1 = iR1 + 1
        Else
            iR2 = iR2 + 1
        End If
     End If
được phải không ah, vậy cho cách nào linh hoạt hơn không các bạn, anh chị em mới học mảng nhiều khi câu hỏi ngô ghê xin đừng cười ạ. Thanks
Gợi ý như sau:
Do biết trước chỉ có 2 cột, nên ta dùng 2 biến iR1 và iR2
Không biết bao nhiêu cột thì dùng biến mảng iR()
ReDim iR(1 To cái gì đó thích hợp, suy nghĩ nha)

Rồi sau đó, j bằng bi nhiu, tăng iR(j) lên 1
rồi ....
 
Upvote 0
Gợi ý như sau:
Do biết trước chỉ có 2 cột, nên ta dùng 2 biến iR1 và iR2
Không biết bao nhiêu cột thì dùng biến mảng iR()
ReDim iR(1 To cái gì đó thích hợp, suy nghĩ nha)

Rồi sau đó, j bằng bi nhiu, tăng iR(j) lên 1
rồi ....

Dựa vào cách Thầy hướng dẫn em làm được file này lọc những ô có năm 2001, em nghĩ nó cũng giống cái lấy số lẻ. Mong Thầy và các bạn hướng dẫn giúp.Thanks
PHP:
Sub locdulieu1()
Dim mang, smang(), li As Long, lj As Long, lr As Long, rmang(), lm As Long
mang = [a1:d28]
ReDim smang(1 To UBound(mang, 1), 1 To UBound(mang, 2))
For li = 1 To UBound(mang, 2)
    For lj = 1 To UBound(mang, 1)
        If lj = 1 Then
        lr = lr + 1
        lm = 0
        End If
        ReDim rmang(1 To lr)
        If mang(lj, li) = "2001" Then
        smang(lm + 1, UBound(rmang, 1)) = mang(lj, li)
        lm = lm + 1
        End If
    Next
Next
[f1].Resize(UBound(mang, 1), UBound(mang, 2)) = smang
End Sub
 
Upvote 0
Như vậy sẽ gọn hơn:
PHP:
Sub locdulieu2()
Dim mang, smang(), li As Long, lj As Long, rmang() As Long
mang = [a1:d28]
ReDim smang(1 To UBound(mang, 1), 1 To UBound(mang, 2))
        ReDim rmang(1 To UBound(mang, 2))
For li = 1 To UBound(mang, 2)
    For lj = 1 To UBound(mang, 1)
        If mang(lj, li) = "2001" Then
        smang(rmang(li) + 1, li) = mang(lj, li)
        rmang(li) = rmang(li) + 1
        End If
    Next
Next
[f1].Resize(UBound(mang, 1), UBound(mang, 2)) = smang
End Sub
Khỏi cần lờ mờ, lờ rờ gì sất.
 
Lần chỉnh sửa cuối:
Upvote 0
Như vậy sẽ gọn hơn:
PHP:
Sub locdulieu2()
Dim mang, smang(), li As Long, lj As Long, rmang() As Long
mang = [a1:d28]
ReDim smang(1 To UBound(mang, 1), 1 To UBound(mang, 2))
        ReDim rmang(1 To UBound(mang, 2))
For li = 1 To UBound(mang, 2)
    For lj = 1 To UBound(mang, 1)
        If mang(lj, li) = "2001" Then
        smang(rmang(li) + 1, li) = mang(lj, li)
        rmang(li) = rmang(li) + 1
        End If
    Next
Next
[f1].Resize(UBound(mang, 1), UBound(mang, 2)) = smang
End Sub
Khỏi cần lờ mờ, lờ rờ gì sất.
ReDim rmang(1 To UBound(mang, 2)). Theo em hiểu cái này tương đương với Redim rmang(1 to 4) là 4 dòng 1 cột. Còn rmang(li) = rmang(li)+1 Nếu em xét theo từng cột đi hen ví dụ cột từ A1:A28 có xuất hiện 10 số 2001 đi thì rmang(li) nó nhảy từ 1 đến 10 mà trong khi Redim rmang có từ 1 đến 4 mà không bị lỗi ta. Em có lờ mờ lờ sờ lắm mong Thầy giải thích thêm. Thanks
 
Upvote 0
Ẹc ẹc,
1.
ReDim rmang(1 To UBound(mang, 2))
tức là
ReDim rmang(1 To 4)
vậy
rmang là mảng 1 chiều
nên
là mảng ngang
4 phần tử
sử dụng
tương ứng
4
cột

2. rmang(li) là giá trị phần tử thứ li, có thể thay đổi giá trị các phần tử đến bao nhiêu chẳng được?

3. đâu phải rmang(li) = 8 là phần tử thứ 8? Nên nhớ li chỉ chạy từ 1 đến 4 trong vòng lặp for thứ nhất.

TB:
lờ mờ là biến lm, lờ rờ là biến lr, ý là không cần 2 biến này nữa í!
 
Lần chỉnh sửa cuối:
Upvote 0
Ẹc ẹc,
1.
ReDim rmang(1 To UBound(mang, 2))
tức là
ReDim rmang(1 To 4)
vậy
rmang là mảng 1 chiều nên là mảng ngang 4 phần tử sử dụng tương ứng 4 cột
TB:
lờ mờ là biến lm, lờ rờ là biến lr, ý là không cần 2 biến này nữa í!
Ặc...ặc.... Khi mình khai báo ReDim rmang(1 To 4) thì nó làm mảng 1 chiều em mới biết em cứ tưởng nó giống mình khai bao này rmang(A1:A10) chứ
rmang(li) là giá trị phần tử thứ li, có thể thay đổi giá trị các phần tử đến bao nhiêu chẳng được?
Vậy cái này thay đổi bao nhiêu cũng được hả Thầy /-*+//-*+/
3. đâu phải rmang(li) = 8 là phần tử thứ 8? Nên nhớ li chỉ chạy từ 1 đến 4 trong vòng lặp for thứ nhất.
Cái này em biết tại em thắc mắc chạy không báo lỗi nên giờ mới hiểu ra mà cũng chưa hiều cho lắm ục...uc..+-+-+-+. Em nghĩ tới đây là đủ rồi để dành cho các bạn khác hỏi nữa, hỏi hoài Thầy cũng kỳ ặc...ặc....Thanks Thầy Mỹ nhiều ;;;;;;;;;;;}}}}}
 
Upvote 0
Web KT
Back
Top Bottom