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ị
 
Hổng biết ý anh có phải là gộp 4 mảng ấy thành Arr(1 to n, 1 to 4) không nhỉ? ---> Mảng này nếu gán vào bảng tính thì mỗi cột của nó sẽ đúng = 1 mảng con
Nếu không phải như em suy đoán thì anh cứ đưa ví dụ cụ thế lên đi
Tối qua mình làm được rồi,đánh vật với thằng mảng này đau đầu, không dám mang file lên cơ quan (sợ lo mãi mê rồi bỏ việc), để tạo được bốn mảng này phải qua nhiều bước xử lý dữ liệu lằng ngoằng, trong đó có ứng dụng hàm của ndu tại đây. (bài của mình cũng gần giống bài của topic đó, chỉ khác là dữ liệu định mức nằm trên nhiều sheet của một file khác,và mình duyệt toàn bộ mã hiệu của sheet khối lượng một lần, dùng dic, left, right, Ucase ... kiểm tra mã hiệu thuột dạng nào mới lấy định mức của sheet tương ứng (xây lắp, sửa chữa, lắp đặt, khảo sát ...) trong file định mức).
Code đại khái là: (Mình nói thuật toán thôi)

Sub ...

....

For i= 1 to dòng cuối

.....
Arr1 = ... ' Chứa mã hiệu
Arr2 = ... ' Chứa tên công việc, tên vật liệu, nhân công ....
Arr3 = ... ' Chứa đơn vị vật liệu, nhân công...
Arr4 = ... ' Chứa định mức vật liệu, nhân công...

...............'Chuyển các Arr1,2,3,4 thành mảng ngang

For j = 1 to n ' n = chiều dài của Arr1 '(cũng là chiều dài của các Arr2,3,4)

k=h+j

ReDim Preserve ArrTong1(k) = Arr1(j)
ReDim Preserve ArrTong2(k) = Arr2(j)
ReDim Preserve ArrTong3(k) = Arr3(j)
ReDim Preserve ArrTong4(k) = Arr4(j)

Next j

h = k

.......

Next i

.............. ' chuyển các ArrTong thành mảng dọc, gán xuống Range
.............

End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Em có đọc 1 bài của anh LeVanDuyet về mảng mà quen đường dẫn tìm trên diễn đàn mà không thấy trong đó có đoạn code như thế này với range (a1:a10) có giá trị từ 1 đến 10
PHP:
Sub mang1()
Dim mang(1 To 10, 1) As Variant, i As Long
For i = 1 To 10
mang(i, 1) = Cells(i, 1)
Next i
[c1:c10] = mang
End Sub
Theo em đọc chủ đề này là mảng 2 chiều 10 dòng và 1 cột, Nếu mình khải báo mảng mang(1 to 10, 1)sẽ tạo mảng 2 chiều, mà mảng 2 chiều là "mảng dọc" vì vậy để muốn cho [c1:c10] có giá trị giống [a1:a10] thì mình phải dùng vòng lập trên không biết có phải không?
PHP:
Dim mang As Variant
mang = [a1:a10].Value
[C1:C10] = mang
Mà khi em thử với code này vẫn ra kết quả mong muốn, theo em hiểu nếu mình khai mang như đoạn code này thì nó luôn tạo mảng 2 chiều như Thấy Mỹ nói ở bài #5 vậy sao không dùng đoạn code này mà phải dùng đoạn code trên mà kết quả không khác nhau???. Mong ACE trên diễn đàn giải thích giúp em có mơ mơ về mảng không hiểu gì lắm có gì mong ACE bỏ qua.Thanks
 
Upvote 0
Em có đọc 1 bài của anh LeVanDuyet về mảng mà quen đường dẫn tìm trên diễn đàn mà không thấy trong đó có đoạn code như thế này với range (a1:a10) có giá trị từ 1 đến 10
PHP:
Sub mang1()
Dim mang(1 To 10, 1) As Variant, i As Long
For i = 1 To 10
mang(i, 1) = Cells(i, 1)
Next i
[c1:c10] = mang
End Sub
Theo em đọc chủ đề này là mảng 2 chiều 10 dòng và 1 cột, Nếu mình khải báo mảng mang(1 to 10, 1)sẽ tạo mảng 2 chiều, mà mảng 2 chiều là "mảng dọc" vì vậy để muốn cho [c1:c10] có giá trị giống [a1:a10] thì mình phải dùng vòng lập trên không biết có phải không?
PHP:
Dim mang As Variant
mang = [a1:a10].Value
[C1:C10] = mang
Mà khi em thử với code này vẫn ra kết quả mong muốn, theo em hiểu nếu mình khai mang như đoạn code này thì nó luôn tạo mảng 2 chiều như Thấy Mỹ nói ở bài #5 vậy sao không dùng đoạn code này mà phải dùng đoạn code trên mà kết quả không khác nhau???. Mong ACE trên diễn đàn giải thích giúp em có mơ mơ về mảng không hiểu gì lắm có gì mong ACE bỏ qua.Thanks
Đây chỉ là ví dụ thôi, tùy trường hợp cụ thể mà dùng. Trường hợp thứ 2, lấy giá trị từ range này sang range khác thì cần gì vòng lập
Dùng vòng lập chăng là trong quá trình di dời, ta có tính toán hoặc biến đổi gì đó
-------------
Mà hình như code của bạn thiếu cái gì đó
- Một là phải khai báo theo kiểu Dim mang(1 to 10, 1 to 1)
- Hai là: Nếu giữ nguyên kiểu mang(1 to 10, 1) thì trên đầu code phải có dòng Option Base 1
 
Upvote 0
Đây chỉ là ví dụ thôi, tùy trường hợp cụ thể mà dùng. Trường hợp thứ 2, lấy giá trị từ range này sang range khác thì cần gì vòng lập
Dùng vòng lập chăng là trong quá trình di dời, ta có tính toán hoặc biến đổi gì đó
Vậy anh cho em xin 1 ví dụ nho nhỏ để em hiểu thêm về nó hen. Thanks
Mà hình như code của bạn thiếu cái gì đó
- Một là phải khai báo theo kiểu Dim mang(1 to 10, 1 to 1)
- Hai là: Nếu giữ nguyên kiểu mang(1 to 10, 1) thì trên đầu code phải có dòng Option Base 1
Anh nói đoạn code thứ 2 phải không anh, mà sao nó vẫn hiểu nó hay thiệt chứ. Mà chắc mang( 1 to n, 1 to m,...) cái này rất quan trọng phải không anh, vì em thấy nếu khai báo mang (1 to 10) thì nó sẽ là mảng 1 chiều liền??
 
Upvote 0
Vậy anh cho em xin 1 ví dụ nho nhỏ để em hiểu thêm về nó hen. Thanks
Ví dụ thế này:
- A1:A10 chứa các số nào đó
- Dùng vòng lập lấy các số lẻ trong A1:A10 và chuyển sang cột C
Đương nhiên ta có tính toán (để biết số nào lẻ) chứ không chuyển nguyên vùng nên buộc phải vòng lập rồi
PHP:
Sub Test()
  Dim sArray, Arr(), i As Long, j As Long
  sArray = Range("A1:A10").Value
  ReDim Arr(1 To UBound(sArray), 1 To 1)
  For i = 1 To UBound(sArray)
    If sArray(i, 1) Mod 2 Then
       j = j + 1
      Arr(j, 1) = sArray(i, 1)
    End If
  Next
  Range("C1:C10") = Arr
End Sub


Anh nói đoạn code thứ 2 phải không anh, mà sao nó vẫn hiểu nó hay thiệt chứ. Mà chắc mang( 1 to n, 1 to m,...) cái này rất quan trọng phải không anh, vì em thấy nếu khai báo mang (1 to 10) thì nó sẽ là mảng 1 chiều liền??
Chú ý rằng mang( 1 to n, 1 to m) khác với mang(n, m) ---> Cái đầu thì vị trí phần tử đầu tiên được tính từ 1, còn cái sau, vị trí của phần tử đầu tiên được tính từ 0. Vậy mang(n, m) <===> mang(0 to n, 0 to m)
Có những mảng mà ta không khống chế được chỉ số của phần tử đầu tiên. Ví dụ:
- Mảng lấy từ 1 list của ListBox, ComboBox thì phần tử đầu tiên luôn bắt đầu bằng 0
- Mảng lấy từ Range thì phần tử đầu tiên luôn bắt đầu từ 1

Tóm lại: Chỉ có thể khống chế được chỉ số của phần tử đầu tiên đối với những mảng do chính ta tạo ra
 
Upvote 1
Ví dụ thế này:
- A1:A10 chứa các số nào đó
- Dùng vòng lập lấy các số lẻ trong A1:A10 và chuyển sang cột C
Đương nhiên ta có tính toán (để biết số nào lẻ) chứ không chuyển nguyên vùng nên buộc phải vòng lập rồi
Em hiểu như thế này có đúng không mảng (Array) sẽ nạp những ô nào là lẽ ở vùng A1:A10 vào trong Array tức là {1,3,5,7,9} với thứ tự này nó sẽ bung ra ở vùng B1:B10 thật ra mình chỉ cần B1:B5 là đủ rồi, mà sao có khi em nạp dữ liệu vào mạng khi bung ra có xuất hiện chữ #N/A là sao anh
PHP:
Sub Test()
  Dim sArray, Arr(), i As Long, j As Long
  sArray = Range("A1:B10").Value
  ReDim Arr(1 To UBound(sArray), 1 To UBound(sArray,2))
  For i = 1 To UBound(sArray)
    If sArray(i, 1) Mod 2 Then
        j = j + 1
      Arr(j, 1) = sArray(i, 1)
      Arr(j, 2) = sArray(i, 2)
   End If
  Next
  Range("C1:D10") = Arr
End Sub
Với đoạn code này em sẽ lấy nhưng số lẽ ở vùng A1:B10 với B1:B10 giá trị từ 11 đến 20 vậy mình có cách nào ngắn hơn hay không anh. Thanks
 
Lần chỉnh sửa cuối:
Upvote 0
Em hiểu như thế này có đúng không mảng (Array) sẽ nạp những ô nào là lẽ ở vùng A1:A10 vào trong Array tức là {1,3,5,7,9} với thứ tự này nó sẽ bung ra ở vùng B1:B10 thật ra mình chỉ cần B1:B5 là đủ rồi, mà sao có khi em nạp dữ liệu vào mạng khi bung ra có xuất hiện chữ #N/A là sao anh
PHP:
Sub Test()
  Dim sArray, Arr(), i As Long, j As Long
  sArray = Range("A1:B10").Value
  ReDim Arr(1 To UBound(sArray), 1 To UBound(sArray,2))
  For i = 1 To UBound(sArray)
    If sArray(i, 1) Mod 2 Then
        j = j + 1
      Arr(j, 1) = sArray(i, 1)
      Arr(j, 2) = sArray(i, 2)
   End If
  Next
  Range("C1:D10") = Arr
End Sub
Với đoạn code này em sẽ lấy nhưng số lẽ ở vùng A1:B10 với B1:B10 giá trị từ 11 đến 20 vậy mình có cách nào ngắn hơn hay không anh. Thanks
Theo tôi thì code dài ngắn mà mình hiểu là OK.
Báo NA là do khai báo ReDim Arr(1 To UBound(sArray), mà UBound(sArray) là 10 trong khi đó ta chỉ lấy sổ lẻ là có 5 thôi.
Vậy code trên sửa lại thế này, mình chi lấy theo j dòng thôi, ie nếu thỏa thì j=j+1.
PHP:
Sub Test() 
  Dim sArray, Arr(), i As Long, j As Long 
  sArray = Range("A1:B10").Value 
  ReDim Arr(1 To UBound(sArray), 1 To UBound(sArray,2)) 
j=0
  For i = 1 To UBound(sArray) 
    If sArray(i, 1) Mod 2 Then 
        j = j + 1 
      Arr(j, 1) = sArray(i, 1) 
      Arr(j, 2) = sArray(i, 2) 
   End If 
  Next 
  Range("C1").resize(j,2) = Arr 
End Sub
 
Upvote 0
Em hiểu như thế này có đúng không mảng (Array) sẽ nạp những ô nào là lẽ ở vùng A1:A10 vào trong Array tức là {1,3,5,7,9} với thứ tự này nó sẽ bung ra ở vùng B1:B10 thật ra mình chỉ cần B1:B5 là đủ rồi, mà sao có khi em nạp dữ liệu vào mạng khi bung ra có xuất hiện chữ #N/A là sao anh

Với đoạn code này em sẽ lấy nhưng số lẽ ở vùng A1:B10 với B1:B10 giá trị từ 11 đến 20 vậy mình có cách nào ngắn hơn hay không anh. Thanks

Với cả 2 thí dụ trên, ta đã biết trước trong 10 ô có 5 số lẻ, trong 20 ô có 10 số lẻ.
Thực chất ta không biết trước chuyện này, nên vẫn phải khai báo mảng với kích thước tối thiểu bằng với mảng gốc.
Ngoài ra, số số lẻ trong cột A chưa chắc bằng số số lẻ cột B, và chưa chắc nó nằm ngang hàng. Nếu cho 1 vùng số bất kỳ thì không thể dùng code trên mà phải 2 vòng lặp: 1 cho cột và 1 cho dòng.

Nếu dùng Scripting Dictionary ta sẽ giới hạn được phần nào mảng dư kích thước, nhưng đó lại là chuyên đề khác.
 
Lần chỉnh sửa cuối:
Upvote 0
Em hiểu như thế này có đúng không mảng (Array) sẽ nạp những ô nào là lẽ ở vùng A1:A10 vào trong Array tức là {1,3,5,7,9} với thứ tự này nó sẽ bung ra ở vùng B1:B10 thật ra mình chỉ cần B1:B5 là đủ rồi, mà sao có khi em nạp dữ liệu vào mạng khi bung ra có xuất hiện chữ #N/A là sao anh
PHP:
Sub Test()
  Dim sArray, Arr(), i As Long, j As Long
  sArray = Range("A1:B10").Value
  ReDim Arr(1 To UBound(sArray), 1 To UBound(sArray,2))
  For i = 1 To UBound(sArray)
    If sArray(i, 1) Mod 2 Then
        j = j + 1
      Arr(j, 1) = sArray(i, 1)
      Arr(j, 2) = sArray(i, 2)
   End If
  Next
  Range("C1:D10") = Arr
End Sub
Với đoạn code này em sẽ lấy nhưng số lẽ ở vùng A1:B10 với B1:B10 giá trị từ 11 đến 20 vậy mình có cách nào ngắn hơn hay không anh. Thanks
Code vậy là được rồi. Có điều A1:B10 đang bố trí có trật tự nên bạn chỉ dùng 1 vòng lập (bạn ngầm hiểu rằng nếu cột 1 là số lẻ thì cột 2 cũng là số lẻ). Trong trường hợp A1:B10 chứa số tùy ý và không theo trật tự nào thì bạn buộc phải dùng 2 vòng lập (duyệt từ trên xuống và từ trái qua phải)
PHP:
Sub Test1()
  Dim sArray, Arr(), i As Long, j As Long, iR As Long
  sArray = Range("A1:B10").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(Int(iR / 2) + 1, (iR Mod 2) + 1) = sArray(i, j)
        iR = iR + 1
     End If
    Next
  Next
  Range("C1:D10") = Arr
End Sub
Thử xem!
 
Lần chỉnh sửa cuối:
Upvote 1
Thay đổi kích thước mảng 2 chiều

Nhân tiện có bài này cho các bạn thực hành về mảng 2 chiều: Hãy xây dựng 1 hàm Resize2DArray từ 1 mảng 2 chiều cho trước theo cú pháp sau:
PHP:
Function Resize2DArray(ByVal sArray, ByVal rowSize As Long, ByVal colSize As Long)
Mảng kết quả sẽ có kích thước chiều 1 = rowSize và kích thước chiều 2 = colSize (lấy chuẩn Base 1)
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 (Blank <==> Blank cell, không phải "" nha)
Cuối cùng khi đã có hàm Resize2DArray rồi, ta sẽ viết code thực thi theo dạng như sau:
PHP:
Sub Test()
 Dim sArray, Arr
 sArray = Range("A1:C20").Value
 Arr = Resize2DArray(sArray, 30, 6)
 Range("H1:M30").Value = Arr
End Sub
Thử xem, không khó lắm đâu
 
Upvote 0
Nhân tiện có bài này cho các bạn thực hành về mảng 2 chiều: Hãy xây dựng 1 hàm Resize2DArray từ 1 mảng 2 chiều cho trước theo cú pháp sau:
PHP:
Function Resize2DArray(ByVal sArray, ByVal rowSize As Long, ByVal colSize As Long)
Mảng kết quả sẽ có kích thước chiều 1 = rowSize và kích thước chiều 2 = colSize (lấy chuẩn Base 1)
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 (Blank <==> Blank cell, không phải "" nha)
Cuối cùng khi đã có hàm Resize2DArray rồi, ta sẽ viết code thực thi theo dạng như sau:
PHP:
Sub Test()
 Dim sArray, Arr
 sArray = Range("A1:C20").Value
 Arr = Resize2DArray(sArray, 30, 6)
 Range("H1:M30").Value = Arr
End Sub
Thử xem, không khó lắm đâu
Mấy anh tham gia vô đi để em học hỏi với về function kể như là em mù bị knockout rồi, chắc chủ nhật này phải lên HCM để mua sách học rồi tại vì lần trước lặn lội từ dưới quê lên mua mà hết sách buồn quá !$@!!!$@!!
 
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à giới thiệu luôn Code Test3, lấy số lẻ 2 cột và sắp lại dồn thành 1 cột.

PHP:
Sub test3()
  Dim sArray, Arr(), i As Long, j As Long, iR As Long
  sArray = Range("A2:B11").Value
  ReDim Arr(1 To UBound(sArray) * UBound(sArray, 2), 1 To 1)
For j = 1 To UBound(sArray, 2)
    For i = 1 To UBound(sArray, 1)
      If sArray(i, j) Mod 2 Then
      Arr(iR + 1, 1) = sArray(i, j)
      iR = iR + 1
        End If
    Next
  Next
  Range("G2:G" & iR + 1) = Arr
      
End Sub
Nếu để ý, sẽ thấy code Test3 For theo cột nằm ngoài, For theo dòng nằm trong.
Nếu đảo lại For theo cột nằm trong, ta sẽ có kết quả khác (Sub Test4)

Coi như đây là 1 số thí dụ về những cách sử dụng Array 1 cách linh hoạt cho những yêu cầu khác nhau.
 

File đính kèm

  • ArrayLocLe.xls
    36.5 KB · Đọc: 339
Lần chỉnh sửa cuối:
Upvote 0
Đề bài Thay đổi kích thước mảng 2 chiều (bài #30) của ndu sửa lại 1 chút cho phù hợp với thực tế:

Cho 1 vùng dữ liệu cho trước m dòng và n cột, do m quá lớn, sắp xếp lại thành vùng dữ liệu mới có số cột nhiều hơn, để cho số dòng ít lại.
Hoặc nếu nhiều cột quá và muốn sắp xếp gọn lại ít cột hơn, số dòng sẽ nhiều hơn.

Thường thì với vùng dữ liệu ban đầu bất kỳ, khi sắp xếp lại ta chỉ biết rằng ta muốn 5 cột, 10 cột, chứ số dòng không muốn tính trước hoặc tính nhẩm không đúng. Để máy nó tính cho khoẻ.

Vậy Function chỉ có 2 tham số như sau:
PHP:
Function resizeArr(ByVal SourceArr, ByVal NewC As Long)
Dim OldR As Long, OldC As Long, NewR As Long, iR As Long, iC As Long
Dim ArrKQ, iKQ, jKQ
iKQ = 1: jKQ = 1
OldR = UBound(SourceArr, 1)
OldC = UBound(SourceArr, 2)
NewR = Int(OldR * OldC / NewC) 
If (OldR * OldC) Mod NewC > 0 Then NewR = NewR + 1
ReDim ArrKQ(1 To NewR, 1 To NewC)
For iC = 1 To OldC
    For iR = 1 To OldR
        ArrKQ(iKQ, jKQ) = SourceArr(iR, iC)
        iKQ = iKQ + 1
        If iKQ > NewR Then iKQ = 1: jKQ = jKQ + 1
    Next
Next
resizeArr = ArrKQ
End Function
Ghi chú:
Kết quả đang sắp xếp dọc trước, ngang sau. Nếu muốn thay đổi ngang trước dọc sau thì thay
PHP:
        iKQ = iKQ + 1
        If iKQ > NewR Then iKQ = 1: jKQ = jKQ + 1
bằng

PHP:
        jKQ = jKQ + 1
        If jKQ > NewC Then jKQ = 1: iKQ = iKQ + 1
Và dĩ nhiên, ta có thể chọn số cột ít hơn số cột ban đầu, số dòng sẽ tự tính lại để sắp xếp.
 

File đính kèm

  • ResizeArr.xls
    35.5 KB · Đọc: 178
Lần chỉnh sửa cuối:
Upvote 0
Đề bài Thay đổi kích thước mảng 2 chiều (bài #30) của ndu sửa lại 1 chút cho phù hợp với thực tế:

Cho 1 vùng dữ liệu cho trước m dòng và n cột, do m quá lớn, sắp xếp lại thành vùng dữ liệu mới có số cột nhiều hơn, để cho số dòng ít lại.
Hoặc nếu nhiều cột quá và muốn sắp xếp gọn lại ít cột hơn, số dòng sẽ nhiều hơn.

Thường thì với vùng dữ liệu ban đầu bất kỳ, khi sắp xếp lại ta chỉ biết rằng ta muốn 5 cột, 10 cột, chứ số dòng không muốn tính trước hoặc tính nhẩm không đúng. Để máy nó tính cho khoẻ.

Vậy Function chỉ có 2 tham số như sau:
PHP:
Function resizeArr(ByVal SourceArr, ByVal NewC As Long)
Dim OldR As Long, OldC As Long, NewR As Long, iR As Long, iC As Long
Dim ArrKQ, iKQ, jKQ
iKQ = 1: jKQ = 1
OldR = UBound(SourceArr, 1)
OldC = UBound(SourceArr, 2)
NewR = Int(OldR * OldC / NewC) 
If (OldR * OldC) Mod NewC > 0 Then NewR = NewR + 1
ReDim ArrKQ(1 To NewR, 1 To NewC)
For iC = 1 To OldC
    For iR = 1 To OldR
        ArrKQ(iKQ, jKQ) = SourceArr(iR, iC)
        iKQ = iKQ + 1
        If iKQ > NewR Then iKQ = 1: jKQ = jKQ + 1
    Next
Next
resizeArr = ArrKQ
End Function
Ghi chú:
Kết quả đang sắp xếp dọc trước, ngang sau. Nếu muốn thay đổi ngang trước dọc sau thì thay
PHP:
        iKQ = iKQ + 1
        If iKQ > NewR Then iKQ = 1: jKQ = jKQ + 1
bằng

PHP:
        jKQ = jKQ + 1
        If jKQ > NewC Then jKQ = 1: iKQ = iKQ + 1
Và dĩ nhiên, ta có thể chọn số cột ít hơn số cột ban đầu, số dòng sẽ tự tính lại để sắp xếp.
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!
----------------
Nói thêm là 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. Lý do vì thông thường khi tạo mảng ta dùng ReDim Preserve chỉ có thể thay đổi kích thước chiều thứ hai mà chẳng thể làm gì được đối với chiều thứ nhất (trong khi chiều thứ nhất này mới là chiều mà mọi người quan tâm)... Còn cái mà sư phụ đang làm thì có vẽ không giống như ý nghĩa của Resize lắm
Ẹc... Ẹc...
----------------
Xong món này ta sẽ xử tiếp món Office Array
 
Upvote 0
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
Web KT
Back
Top Bottom