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ị
 
2 vòng lập lồng với nhau làm khối lượng duyệt qua các dòng rất lớn, bạn tìm hiểu phương thức Find chỉ dùng 1 vòng lập, hoặc Dictionary dùng 2 vòng lập tách rời ra sẽ nhanh hơn nhiều

PHP:
Sub LookupFunction()
    Application.ScreenUpdating = False
    Dim i As Long, j As Long, lStart As Double, lFinish As Double, k As Long, rRang As Range
    lStart = Timer()
    Sheets("VLK").Range("C1:H65000").ClearContents
    k = Sheets("VLK").Range("B65000").End(xlUp).Row
    Set rRang = Sheets("Data").Range("A5:A5000")

    For i = 1 To k
        If Not rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext) Is Nothing Then
            Cells(i, 3).Value = rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext).Offset(0, 1).Value
            Cells(i, 4).Value = rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext).Offset(0, 2).Value
            Cells(i, 5).Value = rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext).Offset(0, 3).Value
            Cells(i, 6).Value = rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext).Offset(0, 4).Value
            Cells(i, 7).Value = rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext).Offset(0, 5).Value
            Cells(i, 8).Value = rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext).Offset(0, 6).Value
        End If
    Next i
    lFinish = Timer()
    Application.ScreenUpdating = True
   MsgBox "Second: " & (lFinish - lStart), , "Timer"
End Sub

Anh ơi. Em viết dưới dạng mảng chưa được, Em chưa giải quyết được cấu trúc cú pháp của Find function từ Range sang Array.

PHP:
expression .Find(What, After, LookIn, LookAt, SearchOrder, SearchDirection, MatchCase, MatchByte, SearchFormat)

expression A variable that represents a Range object.
Khi áp dụng vào Array, em thay expression từ range thành biến của Array tương ứng vào range, nhưng vẫn chưa được. Anh gợi ý giúp đỡ.
 
Upvote 0
find chỉ dùng cho range
Mã:
Option Explicit

Sub VLK()
  Application.ScreenUpdating = False
  Dim sArr1(), sArr2(), dArr(), Rng As Range, C As Range, firstAddress
  Dim i As Long, LastR As Long, j As Long, lStart As Double, lFinish As Double, k As Long
  lStart = Timer()
  With Sheets("Data")
    Set Rng = .Range("A5:A" & .Range("A" & Rows.Count).End(xlUp).Row)
    sArr2 = .Range("B1:G" & .Range("A" & Rows.Count).End(xlUp).Row).Value
  End With
  With Sheets("VLK")
    .Range("C1:H" & .Range("B" & Rows.Count).End(xlUp).Row).ClearContents
    sArr1 = .Range("B1:B" & .Range("B" & Rows.Count).End(xlUp).Row).Value
  End With
  ReDim dArr(1 To UBound(sArr1), 1 To 6)
  For i = 1 To UBound(sArr1)
    Set C = Rng.Find(sArr1(i, 1), LookIn:=xlValues, Lookat:=xlWhole)
    If Not C Is Nothing Then
      firstAddress = C.Address
      Do
        k = C.Row
        For j = 1 To 6
          dArr(i, j) = sArr2(k, j)
        Next j
        Set C = Rng.FindNext(C)
      Loop While Not C Is Nothing And C.Address <> firstAddress
    End If
  Next i
  Sheets("VLK").Range("C1").Resize(UBound(sArr1), 6).Value = dArr
  lFinish = Timer()
  Application.ScreenUpdating = True
  MsgBox "Second: " & (lFinish - lStart), , "Timer"
End Sub
 
Upvote 0
PHP:
Sub LookupFunction()
    Application.ScreenUpdating = False
    Dim i As Long, j As Long, lStart As Double, lFinish As Double, k As Long, rRang As Range
    lStart = Timer()
    Sheets("VLK").Range("C1:H65000").ClearContents
    k = Sheets("VLK").Range("B65000").End(xlUp).Row
    Set rRang = Sheets("Data").Range("A5:A5000")

    For i = 1 To k
        If Not rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext) Is Nothing Then
            Cells(i, 3).Value = rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext).Offset(0, 1).Value
            Cells(i, 4).Value = rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext).Offset(0, 2).Value
            Cells(i, 5).Value = rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext).Offset(0, 3).Value
            Cells(i, 6).Value = rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext).Offset(0, 4).Value
            Cells(i, 7).Value = rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext).Offset(0, 5).Value
            Cells(i, 8).Value = rRang.Find(Cells(i, 2).Value, , xlValues, , , xlNext).Offset(0, 6).Value
        End If
    Next i
    lFinish = Timer()
    Application.ScreenUpdating = True
   MsgBox "Second: " & (lFinish - lStart), , "Timer"
End Sub

Anh ơi. Em viết dưới dạng mảng chưa được, Em chưa giải quyết được cấu trúc cú pháp của Find function từ Range sang Array.

PHP:
expression .Find(What, After, LookIn, LookAt, SearchOrder, SearchDirection, MatchCase, MatchByte, SearchFormat)

expression A variable that represents a Range object.
Khi áp dụng vào Array, em thay expression từ range thành biến của Array tương ứng vào range, nhưng vẫn chưa được. Anh gợi ý giúp đỡ.
bài nầy dùng Dic nhanh hơn nhiều
Mã:
Option Explicit

Sub VLK1()
  Application.ScreenUpdating = False
  Dim sArr1(), sArr2(), dArr(), Tmp
  Dim i As Long, LastR As Long, j As Long, lStart As Double, lFinish As Double, k As Long
  lStart = Timer()
  With Sheets("Data")
    sArr2 = .Range("A5:G" & .Range("A" & Rows.Count).End(xlUp).Row).Value
  End With
  With Sheets("VLK")
    .Range("C1:H" & .Range("B" & Rows.Count).End(xlUp).Row).ClearContents
    sArr1 = .Range("B1:B" & .Range("B" & Rows.Count).End(xlUp).Row).Value
  End With
  ReDim dArr(1 To UBound(sArr1), 1 To 6)
  With CreateObject("scripting.dictionary")
    For i = 1 To UBound(sArr2)
      .Item(sArr2(i, 1)) = i
    Next i
    For i = 1 To UBound(sArr1)
      Tmp = sArr1(i, 1)
      If .exists(Tmp) Then
        k = .Item(Tmp)
        For j = 1 To 6
          dArr(i, j) = sArr2(k, j + 1)
        Next j
      End If
    Next i
  End With
  Sheets("VLK").Range("C1").Resize(UBound(sArr1), 6).Value = dArr
  lFinish = Timer()
  Application.ScreenUpdating = True
  MsgBox "Second: " & (lFinish - lStart), , "Timer"
End Sub
 
Upvote 0
Hi mọi người. em là thành viên mới. em có đoạn code mà bị lỗi chỗ: Sheets(Array("A1:B9")).Copy. có bác nào cao thủ chỉ giúp em với
Sub myDim()
Application.ScreenUpdating = False
Dim a(7) As String
With ThisWorkbook
maxrow = .Sheets(1).UsedRange.Rows.Count
For t = 2 To maxrow
For i = 1 To 8
a(i - 1) = Sheets(1).Cells(t, i).Value
Next
If a(0) = "" Then
Exit For
Else
.Sheets(2).Activate
.Sheets(2).Range("B1").Value = a(2)
.Sheets(2).Range("B2").Value = a(3)
.Sheets(2).Range("B3").Value = a(4)
.Sheets(2).Range("B4").Value = a(1)
.Sheets(2).Range("B5").Value = a(0)
.Sheets(2).Range("B6").Value = a(5)
.Sheets(2).Range("B8").Value = a(7)
.Sheets(2).Range("B9").Value = a(6)
Sheets(Array("A1:B9")).Copy
ActiveWorkbook.SaveAs Filename:=ThisWorkbook.Path & "\" & a(7) & a(1) & Format(Date, "yyyy"".""m"".""d"""";@") & ".xls"
ActiveWorkbook.Close
End If
Next
End With
Sheets(1).Activate
Application.ScreenUpdating = True
MsgBox "Íê³É"
End Sub
 
Upvote 0
Hi mọi người. em là thành viên mới. em có đoạn code mà bị lỗi chỗ: Sheets(Array("A1:B9")).Copy. có bác nào cao thủ chỉ giúp em với
Sub myDim()
Application.ScreenUpdating = False
Dim a(7) As String
With ThisWorkbook
maxrow = .Sheets(1).UsedRange.Rows.Count
For t = 2 To maxrow
For i = 1 To 8
a(i - 1) = Sheets(1).Cells(t, i).Value
Next
If a(0) = "" Then
Exit For
Else
.Sheets(2).Activate
.Sheets(2).Range("B1").Value = a(2)
.Sheets(2).Range("B2").Value = a(3)
.Sheets(2).Range("B3").Value = a(4)
.Sheets(2).Range("B4").Value = a(1)
.Sheets(2).Range("B5").Value = a(0)
.Sheets(2).Range("B6").Value = a(5)
.Sheets(2).Range("B8").Value = a(7)
.Sheets(2).Range("B9").Value = a(6)
Sheets(Array("A1:B9")).Copy
ActiveWorkbook.SaveAs Filename:=ThisWorkbook.Path & "\" & a(7) & a(1) & Format(Date, "yyyy"".""m"".""d"""";@") & ".xls"
ActiveWorkbook.Close
End If
Next
End With
Sheets(1).Activate
Application.ScreenUpdating = True
MsgBox "Íê³É"
End Sub
Nếu bạn muốn copy vùng A1 B9 của sheet(2) thì thế này

Mã:
.Sheets(2).Range("A1:B9").Copy
 
Upvote 0
Giả sử em làm việc với mảng như sau
dArr(K, 1) = sArr(i, 1)
dArr(K, 2) = sArr(i, 2)
dArr(K, 4) = sArr(i, 4)

Sau đó em gán mảng này bắt đầu từ cell A1 Resize sang 4 cột. Về mặt lý thuyết thì:
A tương đương dArr(K,1)
B tương đương dArr(K,2)
D tương đương dArr(K,4)

Điều em muốn là làm thế nào để cột C không bị tác động bởi dArr(K,3). Nói cách khác mảng sẽ nhảy qua cột C.
 
Upvote 0
Giả sử em làm việc với mảng như sau
dArr(K, 1) = sArr(i, 1)
dArr(K, 2) = sArr(i, 2)
dArr(K, 4) = sArr(i, 4)

Sau đó em gán mảng này bắt đầu từ cell A1 Resize sang 4 cột. Về mặt lý thuyết thì:
A tương đương dArr(K,1)
B tương đương dArr(K,2)
D tương đương dArr(K,4)

Điều em muốn là làm thế nào để cột C không bị tác động bởi dArr(K,3). Nói cách khác mảng sẽ nhảy qua cột C.
bạn làm vấn đề nầy trong những bài tính lương khủng trước đây rồi mà, tạo 2 darr riêng
 
Upvote 0
Giả sử em làm việc với mảng như sau
dArr(K, 1) = sArr(i, 1)
dArr(K, 2) = sArr(i, 2)
dArr(K, 4) = sArr(i, 4)

Sau đó em gán mảng này bắt đầu từ cell A1 Resize sang 4 cột. Về mặt lý thuyết thì:
A tương đương dArr(K,1)
B tương đương dArr(K,2)
D tương đương dArr(K,4)

Điều em muốn là làm thế nào để cột C không bị tác động bởi dArr(K,3). Nói cách khác mảng sẽ nhảy qua cột C.

Là sao ? Là sao???

Có nghĩa là cái cột C của bạn có "bí kíp" gì đó hả??? Dán kết quả không muốn đè lên bí kíp này hay sao?

Nếu như tôi hỏi ở trên thì bắt bạn phải đưa cái cột C này vào mảng dArr trong khi code...
 
Upvote 0
Giả sử em làm việc với mảng như sau
dArr(K, 1) = sArr(i, 1)
dArr(K, 2) = sArr(i, 2)
dArr(K, 4) = sArr(i, 4)

Sau đó em gán mảng này bắt đầu từ cell A1 Resize sang 4 cột. Về mặt lý thuyết thì:
A tương đương dArr(K,1)
B tương đương dArr(K,2)
D tương đương dArr(K,4)

Điều em muốn là làm thế nào để cột C không bị tác động bởi dArr(K,3). Nói cách khác mảng sẽ nhảy qua cột C.

- Chơi như thế này được không?
range("A1")=darr(k,1)

gán từng dòng trên mảng dArr xuống từng cột trên bảng tính Excel./
 
Lần chỉnh sửa cuối:
Upvote 0
Điều em muốn là làm thế nào để cột C không bị tác động bởi dArr(K,3). Nói cách khác mảng sẽ nhảy qua cột C.

1. Copy C sang một mảng khác. Sau khi copy mảng chính thì copy trở lại.
2. Copy dArr xuống 2 cột A và B. Copy dArr(i, 4) sang dArr(i, 1). Copy xuóng cột D
 
Upvote 0
find chỉ dùng cho range
Mã:
Option Explicit

Sub VLK()
  Application.ScreenUpdating = False
  Dim sArr1(), sArr2(), dArr(), Rng As Range, C As Range, firstAddress
  Dim i As Long, LastR As Long, j As Long, lStart As Double, lFinish As Double, k As Long
  lStart = Timer()
  With Sheets("Data")
    Set Rng = .Range("A5:A" & .Range("A" & Rows.Count).End(xlUp).Row)
    sArr2 = .Range("B1:G" & .Range("A" & Rows.Count).End(xlUp).Row).Value
  End With
  With Sheets("VLK")
    .Range("C1:H" & .Range("B" & Rows.Count).End(xlUp).Row).ClearContents
    sArr1 = .Range("B1:B" & .Range("B" & Rows.Count).End(xlUp).Row).Value
  End With
  ReDim dArr(1 To UBound(sArr1), 1 To 6)
  For i = 1 To UBound(sArr1)
    Set C = Rng.Find(sArr1(i, 1), LookIn:=xlValues, Lookat:=xlWhole)
    If Not C Is Nothing Then
      firstAddress = C.Address
      Do
        k = C.Row
        For j = 1 To 6
          dArr(i, j) = sArr2(k, j)
        Next j
        Set C = Rng.FindNext(C)
      Loop While Not C Is Nothing And C.Address <> firstAddress
    End If
  Next i
  Sheets("VLK").Range("C1").Resize(UBound(sArr1), 6).Value = dArr
  lFinish = Timer()
  Application.ScreenUpdating = True
  MsgBox "Second: " & (lFinish - lStart), , "Timer"
End Sub
Kỳ vậy anh, code gốc chạy trong 0.8s, còn code này chay trong 15s. đã test nhiều lần.
 
Upvote 0
Mình có tách như thế này nhưng công nó nhảy không đúng vào ngày, không biết sai ở đâu. Mình cũng chỉ cop nhặt và nhờ sự giúp đỡ của anh em trên này thôi nên có những thứ cơ bản có thể mình vẫn mắc lỗi. Code nằm trong Module Update_cong

tArr(Rws, C) = sArr(i, V1) cái này căn cứ theo C nhưng mà hiện tại nó bị đẩy tiến lên một cột mà mình không biết tại sao.
 

File đính kèm

  • Form cham cong Ver 8 (Office moi) - Copy.xlsb
    1.7 MB · Đọc: 15
Lần chỉnh sửa cuối:
Upvote 0
Là sao ? Là sao???

Có nghĩa là cái cột C của bạn có "bí kíp" gì đó hả??? Dán kết quả không muốn đè lên bí kíp này hay sao?

Nếu như tôi hỏi ở trên thì bắt bạn phải đưa cái cột C này vào mảng dArr trong khi code...

Mình nghĩ có khi nào tách ra làm hai mảng giống như HieuCD cũng đã nói ở trên được không. Hiện tại mình tách thì mảng tArr gán không như ý mình mong muốn. Gán từ Range("J8") thì nhảy chuẩn nhưng mình thắc mắc tại sao như vậy nhỉ? Và nếu bắt buộc phải gán như thế thì J8 coi như phải bỏ trống không dùng được ngoài việc để cho việc gán nó chuẩn. Vậy mảng nào gán vào cột bắt nguồn từ J8 này ??
 
Upvote 0
Em mới học về Array, biến đổi cách dùng hàm Vlookup sang Array.
Các anh góp ý để em thay đổi theo hướng tốt hơn.
PHP:
Sub VLK()
    Application.ScreenUpdating = False
    Dim sArr()
    Dim dArr(1 To 65000, 1 To 6)
    Dim sArr_2()
    Dim i As Long, j As Long, lStart As Double, lFinish As Double, k As Long
    lStart = Timer()
    Sheets("VLK").Range("C1:H65000").ClearContents
    sArr() = Sheets("Data").Range("A5:G65000").Value
    sArr_2 = Sheets("VLK").Range("B1", Range("B65000").End(xlUp)).Value
    k = Sheets("VLK").Range("B65000").End(xlUp).Row
    For i = 1 To k
        For j = 1 To UBound(sArr, 1)
            If sArr_2(i, 1) = sArr(j, 1) Then
                dArr(i, 1) = sArr(j, 2)
                dArr(i, 2) = sArr(j, 3)
                dArr(i, 3) = sArr(j, 4)
                dArr(i, 4) = sArr(j, 5)
                dArr(i, 5) = sArr(j, 6)
                dArr(i, 6) = sArr(j, 7)
                Exit For
            End If
        Next j
    Next i
    Range("C1").Resize(i - 1, 6).Value = dArr
    lFinish = Timer()
    Application.ScreenUpdating = True
   MsgBox "Second: " & (lFinish - lStart), , "Timer"
End Sub

Em cảm thấy vòng lặp For của em, không ổn khi dữ liệu nguồn ngày càng lớn lên.
Mã:
Sub VLK2()
  Application.ScreenUpdating = False
  Dim sArr1(), sArr2(), dArr(), Rng As Range, C As Range, firstAddress
  Dim i As Long, LastR As Long, j As Long, lStart As Double, lFinish As Double, k As Long
  lStart = Timer()
  With Sheets("Data")
    Set Rng = .Range("A5:A" & .Range("A" & Rows.Count).End(xlUp).Row)
    sArr2 = .Range("B5:G" & .Range("A" & Rows.Count).End(xlUp).Row).Value
  End With
  With Sheets("VLK")
    .Range("C1:H" & .Range("B" & Rows.Count).End(xlUp).Row).ClearContents
    sArr1 = .Range("B1:B" & .Range("B" & Rows.Count).End(xlUp).Row).Value
  End With
  ReDim dArr(1 To UBound(sArr1), 1 To 6)
 
 
  Dim lIndex As Long
 
  On Error GoTo loitimkiem
 
  For i = 1 To UBound(sArr1)
    'Set C = Rng.Find(sArr1(i, 1), LookIn:=xlValues, Lookat:=xlWhole)
    
  
    lIndex = Application.WorksheetFunction.Match(sArr1(i, 1), Rng, 0)
    
      If lIndex <> 0 Then
            For j = 1 To 6
              dArr(i, j) = sArr2(lIndex, j)
            Next j
        End If
        

    
  Next i
  Sheets("VLK").Range("C1").Resize(UBound(sArr1), 6).Value = dArr
  lFinish = Timer()
  Application.ScreenUpdating = True
  MsgBox "Second: " & (lFinish - lStart), , "Timer"
 
 
 
  Exit Sub
loitimkiem:
    lIndex = 0
    Resume Next
 
End Sub
 
Upvote 0
Nếu như tôi hỏi ở trên thì bắt bạn phải đưa cái cột C này vào mảng dArr trong khi code...
Nếu cột C có công thức thì lại... phiền
Ủng hộ cách dùng 2 mảng riêng, không đụng chạm gì nhau sẽ không.. mích lòng
 
Upvote 0
Nếu cột C có công thức thì lại... phiền
Ủng hộ cách dùng 2 mảng riêng, không đụng chạm gì nhau sẽ không.. mích lòng

Thầy ơi em dùng hai mảng riêng rồi mà sao em làm không chuẩn ở đâu mà không được như kết quả mong muốn nhỉ. mảng tarr đang bị lệch đi một ô.
 
Upvote 0
Dùng 1 mảng có cái lợi là tách rời phần code tổng hợp dữ liệu ra phỏi phần code ghi lại dữ liệu. Dễ kiểm soát hơn

Range("A1").Resize(Ubound(dArr), 2).Value = dArr ' copy 2 cột đầu xuống cột A và B
For i = 1 to UBound(dArr) ' chuyển giá trị từ cột thứ 4 sang cột 1
dArr(i, 1) = dArr(i, 4)
Next i
Range("D1").Resize(Ubound(dArr), 1).Value = dArr ' copy cột 1 xuống cột D

Dùng 2 mảng có thể nhanh hơn 1chút, vì tiết kiệm được phần chuyển giá trị. Nếu dữ liệu là số thì đoạn này rất nhanh, không thành vấn đề.
 
Upvote 0
Dùng 1 mảng có cái lợi là tách rời phần code tổng hợp dữ liệu ra phỏi phần code ghi lại dữ liệu. Dễ kiểm soát hơn

Range("A1").Resize(Ubound(dArr), 2).Value = dArr ' copy 2 cột đầu xuống cột A và B
For i = 1 to UBound(dArr) ' chuyển giá trị từ cột thứ 4 sang cột 1
dArr(i, 1) = dArr(i, 4)
Next i
Range("D1").Resize(Ubound(dArr), 1).Value = dArr ' copy cột 1 xuống cột D

Dùng 2 mảng có thể nhanh hơn 1chút, vì tiết kiệm được phần chuyển giá trị. Nếu dữ liệu là số thì đoạn này rất nhanh, không thành vấn đề.

Bạn VetMini có thể xem cách mình làm ở bài #812 xem vì sao nó không nhảy đúng được không?
 
Upvote 0
Không biết về đường dài, find có nhanh hơn hay không. Nhưng với dữ liệu hiện tại, thì mảng nhanh hơn đó.
Mã:
    lIndex = Application.WorksheetFunction.Match(sArr1(i, 1), Rng, 0)
xử lý trên range thường chậm hơn trên mảng, dùng find hoặc Match mặc dù code giảm 1 vòng lập nhưng không bù được tốc độ, rất nhiều bài dùng mảng kết hợp Dic là nhanh nhất, nếu dữ liệu phù hợp, như bài nầy không cần dùng Dic vẫn giảm được số vòng lập
 
Upvote 0
Web KT
Back
Top Bottom