• 締切済み

二次元配列が、勝手に一次元配列になってしまう

Excelのマクロで、二次元配列を格納したバリアント型を戻り値とする関数を作ったのですが、… 二次元型配列のひとつの要素数が1の時、受け取ったバリアント型変数は、一次元配列になっています。 列ベクトルなら、それもありかな~と思うのですが、なんで、行ベクトルまで、一次元配列にするんだよ~って、困っています。 シートから関数を呼んだ場合は、列ベクトルは列ベクトル、行ベクトルは行ベクトルとして、表示されるので、マクロの中で関数を呼び出した場合も、行列の情報を保持できる方法があるんじゃないかと思ったのですが。 どなたか、ご教示頂けるとありがたいです。 よろしくお願いします。

みんなの回答

  • chie65535
  • ベストアンサー率43% (8518/19364)
回答No.3

>一番外側のmyMMultにわたってくる引数が1次元配列になってしまいます 何か勘違いしているようですが、ちゃんと2次元配列で返ってきていますよ。 もし、貴方の言う通り、1次元配列で返って来ているというのであれば lcm = UBound(lhs, 2) や rcm = UBound(rhs, 2) の行で「インデックスが有効範囲にありません。」のエラーが出ます。 返って来た値に対しUBound()を使用し、2番目の引数に「2」を指定してもエラーにならないので「返って来た配列の次元数は、少なくとも2以上」である事が証明されます。 貴方の考えが正しければ「UBound関数でエラーが起きる筈」ですが、そういうエラーが起きていないので、結論は「貴方が勘違いしているだけ」です。 以下の関数は「配列の次元数を返す関数」です。 Function GetArrayRank(ary As Variant) As Integer Dim rnk As Integer If IsObject(ary) Then ary = ary.Value rnk = 0 On Error Resume Next Do While Err.Number = 0 rnk = rnk + 1 tmp = UBound(ary, rnk) Loop On Error GoTo 0 GetArrayRank = rnk - 1 End Function この関数に「返って来た値」を引数に渡して「1」が返って来たら、貴方の言うとおり「1次元配列が返って来ている」でしょうけど、間違いなく「2しか返って来ない」ですよ。 もし「GetArrayRankで1が返って来るんですが」って場合は、実際に書いたコードを添えて補足質問を投稿して下さい。 因みに ' LHS count If (IsObject(lhs)) Then lrm = lhs.Rows.Count lcm = lhs.Columns.Count Else lrm = UBound(lhs, 1) lcm = UBound(lhs, 2) End If ' RHS count If (IsObject(rhs)) Then rrm = rhs.Rows.Count rcm = rhs.Columns.Count Else rrm = UBound(rhs, 1) rcm = UBound(rhs, 2) End If の部分は ' LHS count If (IsObject(lhs)) Then lhs = lhs.Value lrm = UBound(lhs, 1) lcm = UBound(lhs, 2) ' RHS count If (IsObject(rhs)) Then rhs = rhs.Value rrm = UBound(rhs, 1) rcm = UBound(rhs, 2) の方が良いです。 これは「オブジェクトが渡されたら、オブジェクトじゃ無くしてしまえ」と言う方法です。 但し「要素数が多いと代入で負荷が大きくなる」ので、要素数が少ない場合にのみ使用します。

  • chie65535
  • ベストアンサー率43% (8518/19364)
回答No.2

追記。 Function SUB1() Dim ary1 As Variant Dim str As String ary1 = SUB2() str = "" For i = 0 To 0 For j = 0 To 9 str = str & ary1(i, j) & "," Next str = str & Chr(13) & Chr(10) Next MsgBox str SUB1 = ary1 End Function Function SUB2() Dim ary2(0 To 0, 0 To 9) As Variant For i = 0 To 0 For j = 0 To 9 ary2(i, j) = (i + 1) * (j + 1) Next Next SUB2 = ary2 End Function のように、行数を1にしても、何も問題は起きませんし Function SUB1() Dim ary1 As Variant Dim str As String ary1 = SUB2() str = "" For i = 0 To 9 For j = 0 To 0 str = str & ary1(i, j) & "," Next str = str & Chr(13) & Chr(10) Next MsgBox str SUB1 = ary1 End Function Function SUB2() Dim ary2(0 To 9, 0 To 0) As Variant For i = 0 To 9 For j = 0 To 0 ary2(i, j) = (i + 1) * (j + 1) Next Next SUB2 = ary2 End Function のように、列数を1にしても、何も問題は起きません。 (前の回答では、0行目、0列目の値が全部0になるので、掛け算の式を変更してあります) どのような状況で再現するのか、補足をお願いします。 因みに「関数から値を受け取る変数」は「配列じゃない、ただのVariant変数」にしないといけませんよ。 もしかして、受け取る変数を配列にしてたりしませんよね?(配列にすると「配列では受け取れない」って意味のエラーになる筈だけど)

koujinkg
質問者

お礼

分かった気がします。 一次元ベクトルは、行ベクトルと考えれば、全て、整合てきですね。 ありがとうございました。

koujinkg
質問者

補足

ご教示ありがとうございます。 会社から書き込めないもので遅くなりまして申し訳ありません。 質問の書き方がよくなかったですが、関数の複数回の呼び出し等のケースです。 たとえば、簡単な例では、行列の掛け算で、VBAコードは、 Function myMMult(lhs As Variant, rhs As Variant) Dim lr As Long, lc As Long, lcm As Long, lrm As Long Dim rc As Long, rcm As Long, rrm As Long Dim ret() As Double, vv As Double ' LHS count If (IsObject(lhs)) Then lrm = lhs.Rows.Count lcm = lhs.Columns.Count Else lrm = UBound(lhs, 1) lcm = UBound(lhs, 2) End If ' RHS count If (IsObject(rhs)) Then rrm = rhs.Rows.Count rcm = rhs.Columns.Count Else rrm = UBound(rhs, 1) rcm = UBound(rhs, 2) End If ' Check consistency If (rrm <> lcm) Then myMMult = "Inconsistent Matrixes" Exit Function End If ReDim ret(1 To lrm, 1 To rcm) For lr = 1 To lrm For rc = 1 To rcm vv = 0 For lc = 1 To lcm vv = vv + lhs(lr, lc) * rhs(lc, rc) Next lc ret(lr, rc) = vv Next rc Next lr myMMult = ret End Function です。 ここで、SheetのCellから、 =myMMult(myMMult(B3:C3,E3:F4),myMMult(H3:I4,K3:K4)) 様な形で呼び出すと、一番外側のmyMMultにわたってくる引数が1次元配列になってしまいます(まあ、このケースでは1次元なんですけど、両方とも列ベクトルになっています) 実際には、行列の掛け算だけではなく、すべてのデータを2次元配列として扱いたいのです。その時、行または列の要素数が1になった場合に、1次元配列になってしまうのを避ける方法はありますでしょうか?

  • chie65535
  • ベストアンサー率43% (8518/19364)
回答No.1

EXCEL2003だと、以下のコードがちゃんと動くので「特に問題はない」と思います。 Function SUB1() Dim ary1 As Variant Dim str As String ary1 = SUB2() str = "" For i = 0 To 9 For j = 0 To 9 str = str & ary1(i, j) & "," Next str = str & Chr(13) & Chr(10) Next MsgBox str SUB1 = ary1 End Function Function SUB2() Dim ary2(0 To 9, 0 To 9) As Variant For i = 0 To 9 For j = 0 To 9 ary2(i, j) = i * j Next Next SUB2 = ary2 End Function どういう場合に問題が出るのでしょう?

関連するQ&A

  • 二次元配列のインデックスについて

    基礎的な質問かもしれませんが、ネットで調べたのですが、うまく回答が見つからなかったので、教えて下さい。 VB.netで二次元配列を扱っているのですが、この要素はどこにあるのかを知りたいのです。 一次元配列でしたら、Indexof を使えば、どこのインデックスに配置されているかが分かると思うのですが、 二次元配列の場合は、どうすればインデックス数が分かるのでしょうか。 例えば、列は0で固定だけど、どこの行にこの要素が格納されているか分からないから、行番号を知りたいと言うときです。 よろしくお願いいたします。

  • 多次元配列の行列

    1番 キーボードから3×3の行列の要素を2次元配列に入力した後、その値を表示するプログラムをさくせいせよ 2番 キーボードから3×4の行列の要素を2次元配列に入力した後、転置行列を出力するプログラムをさくせいせよ 3番 2つの行列A(3×3行列)、B(3×3行列)の買う要素の値をキーボードから2つの配列に入力し、2つの行列、並びに、それらの和、差、積の行列を出力するプログラムを作成せよ(Bに単位行列を入れて検算せよ) 4番 2行3列の行列と3行2列の積を求めるプログラムを作成せよ どなたかわからないでしょうか?? 数が多くてすみません。 わかる方お願いします!!

  • 2次元配列について、教えてください。

    基本的なことなのでしょうがまだよくわかっていません。 ワークシートにたとえると、1次元は縦方向(行番号方向)、二次元は横方向(列番号方向)ですよね? 列数、行数にあたるのが1次元、二次元それぞれの添字ですよね? そしてセルに当たるのが「要素」ですよね? 以上の解釈があっていたら、 1.A列やB列にあたるものはなんと呼ぶのでしょうか? 2.1行目や2行目にあたるのはなんと呼びますか? 3.ワークシートで行や列を削除するような感じで2次元配列の行や列にあたるものを削除することはできますか? 4.UBound関数は、配列の大きさを調べられますが、この大きさは添字です。ワークシートのCells(65536,1).End(xlUp)Rowのように実際にデータがどこまで入っているか調べられますか? 教えてください。 前提とした解釈自体が違っていたらそれもご指摘ください。

  • 二次元配列のサイズについて

    下記のプログラムにおいて、 Public 文字列格納(,) as Variant とか、 Public 文字列格納(,3) as Variant のような、二次元配列を宣言はできないでしょうか? 下記のプログラムは、A1セルに書かれた文字列を、 一文字ずつに分解してB列に転記し、 逆さにしたものを、1文字ずつにC列に転記する プログラムです。A1セルに書かれる文字列の長さは不定です。 本当の目的は、NCBI等から取得したDNAの塩基配列を入力したら、 相補鎖の塩基配列を作成したり、タンパク質に翻訳したり、 乖離エネルギーを計算したりするためのコードで、その一部を 簡単化したものです。 ===プログラムのソース=== Public 文字列格納 As Variant Public 文字列(100, 2) As Variant Sub テスト() 文字列格納 = Cells(1, 1) 長さ = Len(文字列格納) For i = 1 To 長さ 文字列(i, 1) = Mid(文字列格納, i, 1) 文字列(i, 2) = Mid(文字列格納, 長さ - i + 1, 1) Cells(i, 2) = 文字列(i, 1) Cells(i, 3) = 文字列(i, 2) Next i End Sub

  • 2次元配列のnew

    4x4行列のデータがいくらか書いてあるファイルから、読み込んでvector配列へ保存するプログラムを考えています。 vector配列は、float[4][4]の先頭ポインタの配列です。 宣言はこんな感じで、コンパイルエラーは出ませんでした。 vector<float[4][4]> matrix; つぎに読み込み部分で、下のような感じです。 4x4行列が見つかるたびにこれが実行されます。 GetFloatToken()は、ファイルから要素をひとつ取り出す関数です。 float m[4][4] = new float[4][4]; for(int g=0; g<4; g++) for(int r=0; r<4; r++) m[g][r]=GetFloatToken(); matrix.push_back(m); newの行とpush_backしてる行でエラーが出ました。 自分が思うに、m[4][4]のとこの、newからの受け取りの仕方が悪い気がしました。 そこで、*m[4] や **m とかにして試してみましたがうまくいきませんでした。 どうすればいいんでしょうか。 もしかして、c++では多次元配列のnewは無理なんでしょうか。 わかる方がいましたら、どうか教えてください。 補足: あとで行列の計算をするのが楽なので、float[4][4]の形は変えたくないです。 もし、多次元配列のnewが無理ということなら別の策を考えます。

  • 多次元配列のポインタ渡し

    C++を使用しています。 多次元配列を関数の引数として渡したいとき、関数側では void A::Func(int a[10][20][30])~ 呼びだし側では Finc(a); とやればいいのはわかります。 お聞きしたいのは、仮引数として呼び出された配列(上でいうa)をクラスのメンバ変数として保持したい場合の方法です。 aは先頭アドレスなのでそこを差すポインタを受ければいい、っていうことはわかりますが、 この方法ですと、受けたメンバ変数が配列みたいに[]を使ってアクセスできません。 (メンバ変数のポインタは配列じゃないから当然ですよね) これを通常の配列みたいに扱えるようにするにはどうしたらいいでしょうか。

  • 2次元配列の宣言について

    文字列の配列の場合 Dim m As Variant Dim moji As String m=Array("aa","bb","cc","dd",・・・) moji=m(1) とすれば"bb"がmojiに代入されるのはわかるのですが これを二次元配列(3行4列)にする場合どのように 宣言(Dim~や、Array~)等はどのように記述すればよろしいですか? 基本的な質問でごめんなさい。 よろしくお願いします。

  • 二次元配列のソート PHP

    タイトルのとおりソートを行ってくれる関数を探しております。 $buf[][]の二次元配列の変数を日付の降順に並べ替えたいのですが、そういった関数は用意されていますか? sort()、rsort()では不可能かと思います。 以下、二次元配列の値です。配列三番目の日付の降順で再格納したいです。 ( [0] => Array ( [0] => 1[1] => name1 [2] => 2006-08-18 ) [1] => Array ( [0] => 2 [1] => name2[2] => 2006-08-28 ) [2] => Array ( [0] => 3[1] => name3 [2] => 2006-08-18 ) [3] => Array ( [0] => 4 [1] => name4[2] => 2006-08-18 ) よろしくお願いいたします。

    • ベストアンサー
    • PHP
  • 二次元配列の引数渡し

    二次元配列を関数の引数として渡し、 その配列を戻り値として呼び出し元の変数に返したいです。 具体的にはルンゲクッタ法で微分する関数の引数を行列で扱いたいです。 for (i=0;i<N;i++){ for (j=0;j<N;j++){ y[i][j]=rand(); } }   K1=h*ff(t,y); K2=h*ff(t+h/2,y+K1/2); K3=h*ff(t+h/2,y+K2/2); K4=h*ff(t+h,y+K3); Ka=(K1+2*K2+2*K3+K4)/6; double ff(int t,double y[][]){ ここで return y[][]; のような形で二次元配列を戻り値として変数に返したいのです。 } C言語初心者なのでいまいちよくわかりません、 宜しくお願いいたします。

  • ReDimを使用した二次元配列

    全レコードが不明のファイルから、レコードを読み込んで分割し二次元配列に格納したいのですが、項目(列)数は確定しています。この場合は、どうすればレコード(行)数を動的に変更していく事が出来るのでしょうか? ヘルプを見ても、ReDim x(行, 列)だったら、列しか変更出来ないように書いてあって困っています。 どなたか、御教授をお願いします。

専門家に質問してみよう