0

誰かが私にこれを手伝ってくれたら本当にありがたいです。

私は vba に精通しており、簡単なコードを記述したり、他のユーザーのコードをカスタマイズしたりできます。次のことを行うために、いくつかの vba コードを/カスタマイズ/コピーしました (コピーされたソースが認められている場合)。

  1. 同じ列と同じ行の 2 つのマトリックスを表す 2 つの異なる csv ファイルを選択します。
  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
4

2 に答える 2

0

よろしくお願いします。私のコードが結果を出力しなかった理由は、私がこれを持っていたからです:If ANCOLUMNS <> BNROWS Then: GoTo ERROR_LABEL。同時に、70 * 120の2つの行列を使用していたので、プログラムしたとおりに常に関数を終了しました!!すべてを修正して正常に動作しました。あなたの助けをどうもありがとう

于 2012-12-04T10:51:15.010 に答える
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 ;-)

入力と出力の行列の上限と下限を見つけることは、大幅に簡素化できます...

于 2012-12-04T08:33:38.497 に答える