2012-12-04 187 views
0

如果有人可以給我一些幫助,我將非常感激。使用VBA將矩陣相乘並將結果保存在文本文件中

我很熟悉VBA和我可以寫簡單的代碼,並從其他自定義代碼。我已經寫/定製/複製幾件VBA代碼做以下(其中複製請註明出處):

  1. 選擇2個不同的CSV文件,它代表2個矩陣相同的列和相同的行。
  2. 乘以矩陣中的每個單元格。
  3. 返回結果。

不幸的是我不能似乎能夠得到它來運行。 任何想法我沒有做得對嗎? 請參閱下面的代碼。非常感謝。 代碼從以前的版本

Public Sub doIt() 
    Dim sourceFile As String 
    Dim destinationFile As String 
    Dim data As Variant 
    Dim result As Variant 
    Dim sourceFile2 As String 
    Dim datarain As Variant 

    sourceFile = "C:\file1.csv" 
    sourceFile2 = "C:\file2.csv" 
    destinationFile = "C:\file3.txt" 
    data = getDataFromFile(sourceFile, ",") 
    datarain = getDataFromFile(sourceFile2, ",") 
    If Not isArrayEmpty(data) Then 
     result = MMULT2_FUNC(data, datarain) 
     writeToCsv result, destinationFile, "," 
    Else 
     MsgBox ("Empty file") 
    End If 
End Sub 

Function MMULT2_FUNC(ByRef ADATA_RNG As Variant, _ 
ByRef BDATA_RNG As Variant) 

Dim i As Long 
Dim j As Long 
Dim k As Long 

Dim ANROWS As Long 
Dim BNROWS As Long 

Dim ANCOLUMNS As Long 
Dim BNCOLUMNS As Long 

Dim ADATA_MATRIX As Variant 
Dim BDATA_MATRIX As Variant 

Dim TEMP_MATRIX As Variant 

On Error GoTo ERROR_LABEL 

ADATA_MATRIX = ADATA_RNG 
BDATA_MATRIX = BDATA_RNG 

ANROWS = UBound(ADATA_MATRIX, 1) 
BNROWS = UBound(BDATA_MATRIX, 1) 

ANCOLUMNS = UBound(ADATA_MATRIX, 2) 
BNCOLUMNS = UBound(BDATA_MATRIX, 2) 

If ANCOLUMNS <> BNROWS Then: GoTo ERROR_LABEL 

ReDim TEMP_MATRIX(1 To ANROWS, 1 To BNCOLUMNS) 

For i = 1 To ANROWS 
    For j = 1 To BNCOLUMNS 
     TEMP_MATRIX(i, j) = 0 
     For k = 1 To ANCOLUMNS 
      TEMP_MATRIX(i, j) = TEMP_MATRIX(i, j) + ADATA_MATRIX(i, k) * _ 
           BDATA_MATRIX(k, j) 
     Next k 
    Next j 
Next i 

MMULT2_FUNC = TEMP_MATRIX 

Exit Function 
ERROR_LABEL: 
MMULT2_FUNC = Err.Number 
End Function 


Public Sub writeToCsv(parData As Variant, parFileName As String, parDelimiter As String) 

    If getArrayNumberOfDimensions(parData) <> 2 Then Exit Sub 

    Dim i As Long 
    Dim j As Long 
    Dim FileNum As Long 
    Dim locLine As String 
    Dim locCsvString As String 

    FileNum = FreeFile 
    If Dir(parFileName) <> "" Then Kill (parFileName) 
    Open parFileName For Binary Lock Read Write As #FileNum 

    For i = LBound(parData, 1) To UBound(parData, 1) 
     locLine = "" 
     For j = LBound(parData, 2) To UBound(parData, 2) 
     If IsError(parData(i, j)) Then 
      locLine = locLine & "#N/A" & parDelimiter 
     Else 
      locLine = locLine & parData(i, j) & parDelimiter 
     End If 
     Next j 
     locLine = Left(locLine, Len(locLine) - 1) 
     If i <> UBound(parData, 1) Then locLine = locLine & vbCrLf 
     Put #FileNum, , locLine 
    Next i 

error_handler: 
    Close #FileNum 

End Sub 

Public Function isArrayEmpty(parArray As Variant) As Boolean 
'Returns false if not an array or dynamic array that has not been initialised (ReDim) or has been erased (Erase) 

    If IsArray(parArray) = False Then isArrayEmpty = True 
    On Error Resume Next 
    If UBound(parArray) < LBound(parArray) Then isArrayEmpty = True: Exit Function Else: isArrayEmpty = False 

End Function 

Public Function getArrayNumberOfDimensions(parArray As Variant) As Long 
'Returns the number of dimension of an array - 0 for an empty array. 

    Dim i As Long 
    Dim errorCheck As Long 

    If isArrayEmpty(parArray) Then Exit Function 'returns 0 

    On Error GoTo FinalDimension 
    'Visual Basic for Applications arrays can have up to 60000 dimensions 
    For i = 1 To 60001 
     errorCheck = LBound(parArray, i) 
    Next i 

    'Not supposed to happen 
    getArrayNumberOfDimensions = 0 
    Exit Function 

FinalDimension: 
    getArrayNumberOfDimensions = i - 1 

End Function 

Private Function getDataFromFile(parFileName As String, parDelimiter As String, Optional parExcludeCharacter As String = "") As Variant 
'parFileName is supposed to be a delimited file (csv...) 
'parDelimiter is the delimiter, "," for example in a comma delimited file 
'Returns an empty array if file is empty or can't be opened 
'number of columns based on the line with the largest number of columns, not on the first line 
'parExcludeCharacter: sometimes csv files have quotes around strings: "XXX" - if parExcludeCharacter = """" then removes the quotes 


    Dim locLinesList() As Variant 
    Dim locData As Variant 
    Dim i As Long 
    Dim j As Long 
    Dim locNumRows As Long 
    Dim locNumCols As Long 
    Dim fso As Variant 
    Dim ts As Variant 
    Const REDIM_STEP = 10000 

    Set fso = CreateObject("Scripting.FileSystemObject") 

    On Error GoTo error_open_file 
    Set ts = fso.OpenTextFile(parFileName) 
    On Error GoTo unhandled_error 

    'Counts the number of lines and the largest number of columns 
    ReDim locLinesList(1 To 1) As Variant 
    i = 0 
    Do While Not ts.AtEndOfStream 
    If i Mod REDIM_STEP = 0 Then 
     ReDim Preserve locLinesList(1 To UBound(locLinesList, 1) + REDIM_STEP) As Variant 
    End If 
    locLinesList(i + 1) = Split(ts.ReadLine, parDelimiter) 
    j = UBound(locLinesList(i + 1), 1) 'number of columns 
    If locNumCols < j Then locNumCols = j 
    If j = 13 Then 
     j = j 
    End If 
    i = i + 1 
    Loop 

    ts.Close 

    locNumRows = i 

    If locNumRows = 0 Then Exit Function 'Empty file 

    ReDim locData(1 To locNumRows, 1 To locNumCols + 1) As Variant 

    'Copies the file into an array 
    If parExcludeCharacter <> "" Then 

    For i = 1 To locNumRows 
     For j = 0 To UBound(locLinesList(i), 1) 
     If Left(locLinesList(i)(j), 1) = parExcludeCharacter Then 
      If Right(locLinesList(i)(j), 1) = parExcludeCharacter Then 
      locLinesList(i)(j) = Mid(locLinesList(i)(j), 2, Len(locLinesList(i)(j)) - 2)  'If locTempArray = "", Mid returns "" 
      Else 
      locLinesList(i)(j) = Right(locLinesList(i)(j), Len(locLinesList(i)(j)) - 1) 
      End If 
     ElseIf Right(locLinesList(i)(j), 1) = parExcludeCharacter Then 
      locLinesList(i)(j) = Left(locLinesList(i)(j), Len(locLinesList(i)(j)) - 1) 
     End If 
     locData(i, j + 1) = locLinesList(i)(j) 
     Next j 
    Next i 

    Else 

    For i = 1 To locNumRows 
     For j = 0 To UBound(locLinesList(i), 1) 
     locData(i, j + 1) = locLinesList(i)(j) 
     Next j 
    Next i 

    End If 

    getDataFromFile = locData 

    Exit Function 

error_open_file:     'returns empty variant 
unhandled_error:     'returns empty variant 

End Function 
+3

'不幸的是,我似乎無法得到這個運行'然後請再試一次。調試並嘗試隔離問題並用任何錯誤消息更新您的問題。 SO不是調試服務。 –

+0

我的版本實際上正在運行。我的問題是它不打印輸出文件。 – Mary

+0

看,這應該在問題中去!它沒有在任何地方說出問題所在。所以你的問題相當於_help我調試此代碼_... :) –

回答

0

改變儘管我個人的印象是,你的代碼可以在某些情況下得到改善,這句法執行這裏沒有問題(小矩陣)。

我的測試數據

1,2,3  2,3,4  20,26,32 
2,3,4 X 3,4,5 = 29,38,47 
3,4,5  4,5,6  38,50,62 

結果被整齊地寫入到CSV。

只有明顯的問題(這裏在Win 7!)是Sub writeToCsv -> Open parFileName ...未能由於缺乏寫入權限到根目錄下。這可能不是XP上的問題。

從另一個角度來看,我的印象是可以改進代碼,但我可能不瞭解代碼某些部分背後的基本原理。

例子

Function MMULT2_FUNC(ByRef ADATA_RNG As Variant, ByRef BDATA_RNG As Variant) ' missing type of result 

Private Function getDataFromFile(...) 
... 
If j = 13 Then 
    j = j 
End If ' whow ... if j <> 13 then j again equals j ;-) 

發現在輸入和輸出矩陣的上限和下限可通過大簡化...

+1

非常感謝。我知道我的代碼並不完美,我試圖緩慢而穩定地改進。感謝您的評論,這讓我覺得可能是我的工作不正常,因爲它不是同一列和行的數字。所以設法解決問題:) – Mary

0

感謝大家的幫助。我的代碼沒有打印結果的原因是我有這樣的:If ANCOLUMNS <> BNROWS Then: GoTo ERROR_LABEL。與此同時,我使用了兩個70 * 120的矩陣,所以它不斷退出函數,因爲我已經編程它做了!!更正了它並且工作正常。非常感謝您的幫助

相關問題