2016-09-12 11 views
1

以下は、配列と範囲を一様に処理するために書いたコードです(Accepting a range as an array parameter)。これには、という名前の関数が含まれています。これは、数字のの2Dコレクションで呼び出すことができ、同じ数値を2次元配列の倍数として返す関数です。1次元配列から1次元配列への変換を中止する

Public Function item(ByRef A As Variant, i As Integer, j As Integer) As Double 
    If TypeName(A) = "Range" Then 
     item = A.Cells(i, j) 
    Else 
     item = A(i, j) 
    End If 
End Function 

Public Function rows(ByRef A As Variant) As Integer 
    If TypeName(A) = "Range" Then 
     rows = A.rows.Count 
    Else 
     rows = UBound(A, 1) - LBound(A, 1) + 1 
    End If 
End Function 

Public Function cols(ByRef A As Variant) As Integer 
    If TypeName(A) = "Range" Then 
     cols = A.columns.Count 
    Else 
     cols = UBound(A, 2) - LBound(A, 2) + 1 
    End If 
End Function 

Public Function sanitise(ByRef A As Variant) As Double() 

    Debug.Print TypeName(A) 

    If TypeName(A) = "Double()" Then 
     sanitise = A 
    Else 
     Debug.Print rows(A) 

     Dim B() As Double 
     ReDim B(1 To rows(A), 1 To cols(A)) 

     Dim i As Integer, j As Integer 
     For i = 1 To rows(A) 
      For j = 1 To cols(A) 
       B(i, j) = item(A, i, j) 
      Next j 
     Next i 

     sanitise = B 
    End If 
End Function 

実装は、あなたがそれを期待どおりに動作します:ワークシートの範囲を選択し、A1:B2を言って、コールはそれに消毒するとあなたは同じことの2つのコピーがあります:

enter image description here

しかし、何が問題になるのですか。sanitise^2です。

sanitiseを2回コールすると、が呼び出されます()。複数の行:細かい、単一の列:細かい。それがなぜ起こるか

enter image description here

は、私が知っている:最初のsanitiseた後、どのような形状のアレイのExcel忘れが返されました。 (タイプも忘れています:Double()の代わりに、sanitiseの入力はVariant()です)

誰もこの問題を回避する方法を知っていますか?

sanitiseを2度続けて使用することはまずありませんが、上記の例は、2次元配列に沿って2つの関数を作成することが難しい理由を示しています。

注:この問題は、sanitiseがワークシートから呼び出されたときにのみ発生します。

アップデートは、私がそれを考え出した:行と同義でワークシートの1Dストレージ、ためので考慮する必要があること

私の最終バージョン:

Public Function get_2D(ByRef A As Variant) As Double() 
    'turns various forms of input into a 2D array of Doubles 
    Dim result() As Double 
    Dim i As Integer 
    If TypeOf A Is Range Or dims(A) = 2 Then 
     ReDim result(1 To rows(A), 1 To cols(A)) 
     Dim j As Integer 
     For i = 1 To rows(A) 
      For j = 1 To cols(A) 
       result(i, j) = item(A, i, j) 
      Next j 
     Next i 
    Else 
     '1D storage is treated as a row 
     ReDim result(1 To 1, 1 To rows(A)) 'rows(A) gets length of the first axis 
     For i = 1 To rows(A) 
      result(1, i) = A(i) 
     Next i 
    End If 

    sanitise = result 
End Function 

dimsがあります配列の次元数を返す関数:https://support.microsoft.com/en-us/kb/152288

+1

' 'あなたのDebug.Print行(A)の後に'あなたがいることがわかります外側の 'sanitise'が実行されたとき、つまり' cols(A) 'を呼び出している間にクラッシュしたときに何も印刷しません。なぜなら、内部の 'sanitise'は、(1〜1、2〜2)の形の配列を返すからです。なぜなら、渡される前に(1〜2)の形の配列に変換されました外側の '' sanitise''にコードがあり、コードは1次元配列、単なる範囲または2次元配列を扱いません。 – YowE3K

+0

エラーを再現できませんでした。あなたはダウンロードリンクを提供できますか? –

答えて

2

私はこれがあなたの仕様にいくらか似ていると思うし、solviあなたが実証している単一行の問題。それはあなたの目的のために働くでしょうか?

Function sanitise_sugg(inp As Variant) As Variant 
Dim result As Variant 
If TypeOf inp Is Object Then 
result = inp.Value 
Else 
result = inp 
End If 
sanitise_sugg = result 
End Function 

編集:バック一歩を取ると私はあなたが二つに手でタスクを分割すべきだと思う。まず範囲を得意とinterchangeabely配列-VBAのエクセル使用する「sanitise_sugg」を使用します。特殊な必要がある場合は、入力を特定の倍数の配列にする必要がある場合は、テストし、可能であればこの型へのバリアント入力をキャストする別の関数を記述します。

編集2:私の場合にFunction sanitise_sugg(inp As Variant) As Variantに供給される要素は、VBAの中からダブルスを含むと主張させ、代わりに一歩を取って、またはExcelシートから数値を有する細胞、それはspecifciationがPublic Function sanitise(ByRef A As Variant) As Double()

に要求満たし

編集3:関数が入力をどのように追跡しているかを見るbeeingから独立した配列レイアウト行ベクトル、列ベクトル、または完全な行列は、ExcelをVBA内またはExcelから渡したものとは無関係に、以下のワークシートを参照してください;

enter image description here

+0

非常にクール! 'sanitise'の目的は、入力が何であれ、出力が2Dの' Double'配列であることを常に知っていることです。そうすれば、要素へのアクセス方法がわかります。行を渡すと、それは 'B(1、i)'です。 – user357269

+0

仕様が行き過ぎていると思います。あなたの入力が例えばテキスト文字列? "sanitise_sugg"では、行、列、行列のいずれであっても要素にアクセスする方法を知っているという仕様を少なくとも満たしています。 –

+0

おかげでマツ、あなたの答えは本当に何が間違っていたか把握するのに役立ちました!私の質問の一番下に、私が何が起こったかを見るためのアップデートを見てください。 – user357269

0

私はあなたがダブルスの2次元アレイ上の計算の多くを行う場合を除き、このための任意の実用的だと思う、そうすることはできません、あなたがやろうとしている正確に何についての詳細な情報を与える場合は、我々おそらくなど、より良い/より効率的なものに簡単/

.Value.Value2リターン2D Variant配列をお勧めすることができたときに、範囲内の複数のセル:単純なアプローチのCので

v = [a1:b1].Value2 ' Variant/Variant(1 to 1, 1 to 2) 
v = [a1:a2].Value2 ' Variant/Variant(1 to 2, 1 to 1) 
v = [a1].Value2  ' Variant/Double 

ことのようなもの:

Function to2D(v) As Double() 
    'Debug.Print TypeName(v), VarType(v) 
    Dim d2() As Double, r As Long, c As Long 
    If IsArray(v) Then 
     If TypeOf v Is Range Then v = v.Value2 
     ReDim d2(1 To UBound(v, 1), 1 To UBound(v, 2)) 
     For r = 1 To UBound(v, 1) 
      For c = 1 To UBound(v, 2) 
       If IsNumeric(v(r, c)) Then d2(r, c) = v(r, c) 
      Next c 
     Next r 
    Else 
     ReDim d2(1 To 1, 1 To 1) 
     If IsNumeric(v) Then d2(1, 1) = v 
    End If 
    to2D = d2 
End Function 

とでテスト:あなたは `のDebug.Print COLS(A)が含まれている場合

d2 = to2D([a1:b2]) 
d2 = to2D([a1:b1]) 
d2 = to2D([a1:a2]) 
d2 = to2D([a1]) 
d2 = to2D(1) 
d2 = to2D([{" 1 ";" 2.0 "}]) ' works with strings too 
d2 = to2D([{1,2;3,4}]) 
'd2 = to2D([{1,2}]) ' doesn't work with 1D arrays 
+0

これはクールですが、正方形ではありません! '{= to2D(to2D(A1:B1)}}'を試してください – user357269

+0

私は財務データのデータ分析にVBAを使用しています。 – user357269

関連する問題