2012-11-01 12 views
12

Trong Excel qua Visual Basic, tôi đang lặp qua một tệp CSV của hóa đơn được tải vào Excel. Các hóa đơn là một mô hình xác định được bởi khách hàng.Excel VBA - Cách Làm lại một mảng 2D?

Tôi đọc chúng thành một mảng 2D động, sau đó viết chúng vào một trang tính khác có hóa đơn cũ hơn. Tôi hiểu rằng tôi phải đảo ngược các hàng và cột vì chỉ có kích thước cuối cùng của một mảng có thể được Làm lại, sau đó chuyển đổi khi tôi viết nó vào trang tính chính.

Ở đâu đó, tôi có cú pháp sai. Nó vẫn nói với tôi rằng tôi đã Dimensionalized mảng. Bằng cách nào đó tôi đã tạo ra nó như là một mảng tĩnh? Tôi cần phải sửa cái gì để nó hoạt động tự động?

MÃ LÀM VIỆC MỖI ĐÁP ĐƯỢC

Sub InvoicesUpdate() 
' 
'Application Settings 
Application.ScreenUpdating = False 
Application.DisplayAlerts = False 
Application.Calculation = xlCalculationManual 

'Instantiate control variables 
Dim allRows As Long, currentOffset As Long, invoiceActive As Boolean, mAllRows As Long 
Dim iAllRows As Long, unusedRow As Long, row As Long, mWSExists As Boolean, newmAllRows As Long 

'Instantiate invoice variables 
Dim accountNum As String, custName As String, vinNum As String, caseNum As String, statusField As String 
Dim invDate As String, makeField As String, feeDesc As String, amountField As String, invNum As String 

'Instantiate Workbook variables 
Dim mWB As Workbook 'master 
Dim iWB As Workbook 'import 

'Instantiate Worksheet variables 
Dim mWS As Worksheet 
Dim iWS As Worksheet 

'Instantiate Range variables 
Dim iData As Range 

'Initialize variables 
invoiceActive = False 
row = 0 

'Open import workbook 
Workbooks.Open ("path:excel_invoices.csv") 
Set iWB = ActiveWorkbook 
Set iWS = iWB.Sheets("excel_invoices.csv") 
iWS.Activate 
Range("A1").Select 
iAllRows = iWS.UsedRange.Rows.Count 'Count rows of import data 

'Instantiate array, include extra column for client name 
Dim invoices() 
ReDim invoices(10, 0) 

'Loop through rows. 
Do 

    'Check for the start of a client and store client name 
    If ActiveCell.Value = "Account Number" Then 

     clientName = ActiveCell.Offset(-1, 6).Value 

    End If 

    If ActiveCell.Offset(0, 3).Value <> Empty And ActiveCell.Value <> "Account Number" And ActiveCell.Offset(2, 0) = Empty Then 

     invoiceActive = True 

     'Populate account information. 
     accountNum = ActiveCell.Offset(0, 0).Value 
     vinNum = ActiveCell.Offset(0, 1).Value 
     'leave out customer name for FDCPA reasons 
     caseNum = ActiveCell.Offset(0, 3).Value 
     statusField = ActiveCell.Offset(0, 4).Value 
     invDate = ActiveCell.Offset(0, 5).Value 
     makeField = ActiveCell.Offset(0, 6).Value 

    End If 

    If invoiceActive = True And ActiveCell.Value = Empty And ActiveCell.Offset(0, 6).Value = Empty And ActiveCell.Offset(0, 9).Value = Empty Then 

     'Make sure something other than $0 was invoiced 
     If ActiveCell.Offset(0, 8).Value <> 0 Then 

      'Populate individual item values. 
      feeDesc = ActiveCell.Offset(0, 7).Value 
      amountField = ActiveCell.Offset(0, 8).Value 
      invNum = ActiveCell.Offset(0, 10).Value 

      'Transfer data to array 
      invoices(0, row) = "=TODAY()" 
      invoices(1, row) = accountNum 
      invoices(2, row) = clientName 
      invoices(3, row) = vinNum 
      invoices(4, row) = caseNum 
      invoices(5, row) = statusField 
      invoices(6, row) = invDate 
      invoices(7, row) = makeField 
      invoices(8, row) = feeDesc 
      invoices(9, row) = amountField 
      invoices(10, row) = invNum 

      'Increment row counter for array 
      row = row + 1 

      'Resize array for next entry 
      ReDim Preserve invoices(10,row) 

     End If 

    End If 

    'Find the end of an invoice 
    If invoiceActive = True And ActiveCell.Offset(0, 9) <> Empty Then 

     'Set the flag to outside of an invoice 
     invoiceActive = False 

    End If 

    'Increment active cell to next cell down 
    ActiveCell.Offset(1, 0).Activate 

'Define end of the loop at the last used row 
Loop Until ActiveCell.row = iAllRows 

'Close import data file 
iWB.Close 
+0

Tại sao không sử dụng 'invoice = Range (" A1 "). CurrentRegion' thay vì lặp ??? Ngoài ra, tất cả những 'Select' và' ActiveCell' đều chậm và có thể dễ dàng tránh được. –

Trả lời

29

Đây không phải là chính xác trực quan, nhưng bạn không thể ReDim (VB6 Ref) một mảng nếu bạn mờ nó với kích thước. quote chính xác từ trang liên kết là:

Tuyên bố ReDim được sử dụng để kích thước hoặc thay đổi kích thước một mảng động đã đã được chính thức tuyên bố sử dụng một cá nhân, công cộng, hoặc Dim tuyên bố với ngoặc rỗng (không có chiều subscript).

Nói cách khác, thay vì dim invoices(10,0)

Bạn nên sử dụng

Dim invoices() 
Redim invoices(10,0) 

Sau đó, khi bạn ReDim, bạn sẽ cần phải sử dụng Redim Preserve (10,row)

Cảnh báo: Khi Redimensioning đa chiều mảng, nếu bạn muốn giữ lại giá trị của mình, bạn chỉ có thể tăng thứ nguyên cuối cùng. I E. Redim Preserve (11,row) hoặc thậm chí (11,0) sẽ không thành công.

+0

Cảm ơn bạn, điều đó làm sáng tỏ một số rắc rối đối với tôi. Đây là lần đầu tiên tôi sử dụng mảng trong VB. – Liquidgenius

+3

Nhân tiện, ban đầu, tôi đang lặp qua trang tính nhập và chuyển sau khi hoàn tất hóa đơn cho trang tính chính; từng dòng một. Thời gian xử lý mất khoảng 20 phút cho mỗi 1.000 hồ sơ. Sử dụng mảng như là một temp và sau đó viết nó vào master đã giảm quá trình này xuống còn mili giây. Tôi đã thực sự lo lắng trước khi tôi đã quá nóng máy tính của tôi. – Liquidgenius

9

Tôi tình cờ gặp câu hỏi này trong khi tự đánh vào con đường này. Tôi đã kết thúc viết một đoạn mã thực sự nhanh chóng để xử lý ReDim Preserve này trên một mảng có kích thước mới (thứ nguyên đầu tiên hoặc cuối cùng). Có lẽ nó sẽ giúp những người khác đối mặt với cùng một vấn đề.

Vì vậy, để sử dụng, hãy nói rằng bạn có mảng ban đầu được đặt là MyArray(3,5) và bạn muốn làm cho kích thước (đầu tiên quá!) Lớn hơn, chỉ cho phép nói đến MyArray(10,20). Bạn sẽ được sử dụng để làm một cái gì đó như thế này phải không?

ReDim Preserve MyArray(10,20) '<-- Returns Error 

Nhưng không may điều này sẽ trả về lỗi vì bạn đã cố thay đổi kích thước của thứ nguyên đầu tiên. Vì vậy, với chức năng của tôi, bạn sẽ chỉ làm một cái gì đó như thế này thay thế:

MyArray = ReDimPreserve(MyArray,10,20) 

Bây giờ mảng lớn hơn và dữ liệu được giữ nguyên. ReDim Preserve của bạn cho một mảng Đa kích thước hoàn tất.:)

Và cuối cùng nhưng không kém phần quan, chức năng kỳ diệu: ReDimPreserve()

'redim preserve both dimensions for a multidimension array *ONLY 
Public Function ReDimPreserve(aArrayToPreserve,nNewFirstUBound,nNewLastUBound) 
    ReDimPreserve = False 
    'check if its in array first 
    If IsArray(aArrayToPreserve) Then  
     'create new array 
     ReDim aPreservedArray(nNewFirstUBound,nNewLastUBound) 
     'get old lBound/uBound 
     nOldFirstUBound = uBound(aArrayToPreserve,1) 
     nOldLastUBound = uBound(aArrayToPreserve,2)   
     'loop through first 
     For nFirst = lBound(aArrayToPreserve,1) to nNewFirstUBound 
      For nLast = lBound(aArrayToPreserve,2) to nNewLastUBound 
       'if its in range, then append to new array the same way 
       If nOldFirstUBound >= nFirst And nOldLastUBound >= nLast Then 
        aPreservedArray(nFirst,nLast) = aArrayToPreserve(nFirst,nLast) 
       End If 
      Next 
     Next    
     'return the array redimmed 
     If IsArray(aPreservedArray) Then ReDimPreserve = aPreservedArray 
    End If 
End Function 

tôi đã viết này trong giống như 20 phút, do đó không có bảo đảm. Nhưng nếu bạn muốn sử dụng hoặc mở rộng nó, cảm thấy tự do. Tôi đã nghĩ rằng có ai đó đã có một số mã như thế này ở đây rồi, rõ ràng là không. Vì vậy, ở đây ya đi gearheads đồng.

+0

Trông giống như một giải pháp tốt đẹp. Tôi cũng sẽ cố gắng thêm mã này vào mã của mình. Hy vọng rằng nó không phải là quá hiệu suất giết chết như tôi dự định sử dụng điều này trong vòng một vòng lặp. – Luuklag

+1

Điều này làm việc cho tôi. Tuy nhiên, hãy nhớ rằng hàm này không khai báo bất kỳ biến nào, và do đó các mảng của nó được khai báo là 'Các biến thể'. Vì vậy, hãy chắc chắn rằng mảng bạn muốn 'ReDim' cũng được khai báo là' Biến thể', hoặc bạn khai báo các biến của hàm sao cho chúng khớp với kiểu khai báo của các mảng của bạn. – Luuklag

1

đây được cập nhật mã của phương pháp ReDim preseve với khai variabel, hy vọng @Control Freak là tốt với nó :)

Option explicit 
'redim preserve both dimensions for a multidimension array *ONLY 
Public Function ReDimPreserve(aArrayToPreserve As Variant, nNewFirstUBound As Variant, nNewLastUBound As Variant) As Variant 
    Dim nFirst As Long 
    Dim nLast As Long 
    Dim nOldFirstUBound As Long 
    Dim nOldLastUBound As Long 

    ReDimPreserve = False 
    'check if its in array first 
    If IsArray(aArrayToPreserve) Then 
     'create new array 
     ReDim aPreservedArray(nNewFirstUBound, nNewLastUBound) 
     'get old lBound/uBound 
     nOldFirstUBound = UBound(aArrayToPreserve, 1) 
     nOldLastUBound = UBound(aArrayToPreserve, 2) 
     'loop through first 
     For nFirst = LBound(aArrayToPreserve, 1) To nNewFirstUBound 
      For nLast = LBound(aArrayToPreserve, 2) To nNewLastUBound 
       'if its in range, then append to new array the same way 
       If nOldFirstUBound >= nFirst And nOldLastUBound >= nLast Then 
        aPreservedArray(nFirst, nLast) = aArrayToPreserve(nFirst, nLast) 
       End If 
      Next 
     Next 
     'return the array redimmed 
     If IsArray(aPreservedArray) Then ReDimPreserve = aPreservedArray 
    End If 
End Function 
0

Tôi biết đây là một chút cũ nhưng tôi nghĩ rằng có thể có đơn giản hơn nhiều giải pháp không yêu cầu mã hóa bổ sung:

Thay vì chuyển đổi, làm lại và chuyển tiếp lần nữa và nếu chúng ta nói về mảng hai chiều, tại sao không chỉ lưu trữ giá trị được chuyển đổi để bắt đầu. Trong trường hợp đó redim bảo tồn thực sự làm tăng kích thước (thứ hai) ngay từ đầu. Hay nói cách khác, để hình dung nó, tại sao không lưu trữ trong hai hàng thay vì hai cột nếu chỉ có nr của các cột có thể được tăng lên với redim bảo tồn.

các chỉ mục sẽ là 00-01, 01-11, 02-12, 03-13, 04-14, 05-15 ... 0 25-1 25 etcetera thay vì 00-01, 10-11 , 20-21, 30-31, 40-41 etcetera.

Vì chỉ có thứ hai (hoặc cuối cùng) thứ nguyên có thể được bảo tồn trong khi làm lại, có thể có thể cho rằng đây là cách mảng được cho là được sử dụng để bắt đầu. Tôi chưa từng thấy giải pháp này ở bất kỳ đâu nên có thể tôi đang xem cái gì đó?