[[20030710151918]] 『マクロでファンクションへ配列を渡して返す方法』(ろっしい) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『マクロでファンクションへ配列を渡して返す方法』(ろっしい)

マクロでファンクションプロシージャへ配列を渡して返す方法。

配列とファンクションプロシージャを組み合わせて、配列をファンクションプロシージャへ渡して、さらに戻ってきた値を取得するということは可能でしょうか?
やりたいことは、
1.hairetsu(1)〜hairetsu(10) に1〜10の数字が入っている
2.これをファンクションプロシージャへ渡す
3.ファンクションプロシージャの中で各々10倍し、メインに返してくる
というものです。

感じとしては、
Sub親プログラム()

	Dim hairetsu(10) as Integer
	Dim hairetsu_10(10) As Integer

	For i= 1 To 10
		hairetsu(i)=i
	Next
	hairetsu_10 =ファンクションプロシージャ(hairetsu)
End Sub

ファンクションプロシージャ(hairetus_f As Integer ) As Integer

	For j= 1 to 10
		hairetsu_f = hairetsu_f( j ) * 10
	next
	ファンクションプロシージャ = hairetsu_f
End Function

適当にあれこれやってみてはみましたが、いずれも「配列には割り当てられません」と警告が出て止まってしまいます(泣)。上手くいく方法があったらご教授願えると幸いです。
または、とにかく「配列を他のプロシージャに渡して配列として戻す」ということをやりたいだけなので、他の方法で簡単な方法があったら教えていただけると助かります。よろしくお願いします m(__)m


 ご質問の趣旨が今ひとつ理解でけてまへんが、勝手に推測して作ってみました。まち
 がっていたらごめんやで。
  FunctionAは使わなくて(親のfunkAのところにFunctionの式を書く)済みますがあ
 えて使うておきます。
 次にfunkBに置き換えてみて下さい。Functionを使うと便利です(他のプロシージャ
 から参照できますから)。
 それと配列(10)は11個の配列を確保したことになります。なぜなら配列のIndex
 が0から始まるからです。(9)で10個。

     Dim i As Integer
    Dim hairetsu() As Integer, hairetsuA() As Integer, hairetsu_10() As Integer
 ________________________________________
  Sub 親プログラム()
    With Worksheets("sheet1")
    For i = 1 To 10
        ReDim Preserve hairetsu(i)
        ReDim Preserve hairetsu_10(i)
        hairetsu(i) = i
        hairetsu_10(i) = funkA(hairet_f)
        .Cells(i, 1) = hairetsu(i)
        .Cells(i, 2) = hairetsu_10(i)
    Next
    End With
 End Sub
 ________________________________________
 Function funkA(ByVal hairet_f As Integer) As Integer
    ReDim Preserve hairetsu(i)
    hairet_f = i * 10
    funkA = hairet_f
  End Function
 ________________________________________
 Function funkB(ByVal hairet_f As Integer) As Integer
    With Worksheets("sheet1")
    For f = 1 To 10 Step 2

    ReDim Preserve hairetsu(i)
    ReDim Preserve hairetsuA(f)
    hairetsuA(f) = f
    hairet_f = hairetsuA(f) * hairetsu(i) * 10
    .Cells(f, 3) = hairetsuA(f)
    .Cells(f, 3 + i) = hairet_f
    Next
    funkB = hairet_f + 10 * i
    End With
 End Function
  試してみて下さい。(おいぼれ弥太郎)


 こんにちは

 Sub 親プログラム()
     Dim i As Integer
     Dim hairetsu(1 To 10) As Integer
     For i = 1 To 10
         hairetsu(i) = i
         Test hairetsu(i)
         Cells(i, 1).Value = hairetsu(i)
     Next
 End Sub

 Sub Test(hai)
     hai = hai * 10
 End Sub

 少し違うので書いときますね (りな)


おいぼれ弥太郎さん、りなさん、ありがとうございます。

質問の趣旨が曖昧でしたね。すみませんでした。やりたいことは、親プログラムからサブプロシージャ(ファンクションプロシージャ)へ、配列を全部一気に送ってしまい、それを加工した配列を一気に返したいということです。

りなさんのケースだと、一つ一つ配列の要素を渡して、それが一つ一つ帰ってきていますよね。(違っていたらすみません)。おいぼれ弥太郎さんのケースは、私の力量不足で私のやりたいことがどうプログラムされているのかよく理解できていません。明日、入門テキストを買ってきて ReDim や Preserve 等々を勉強します。せっかく丁寧にお答えいただいたのにすぐにお返事できなくてごめんなさい m(__)m  

なぜ要素を一つ一つ送るのではなくて、配列を一気に送りたいかというと、今やっているのは、
5個の要素数を持つ配列 a(1)〜a(5) をファクションプロシージャに送って、そのファクションプロシージャの中で c(1)=a(1)+a(2), c(2)=a(1)+a(5) ・・・・c(5)=a(4)+a(3) 等々、配列の要素を組み合わせて、同じ数の要素数をもつ、a() を加工した配列 c() を作り、さらにそれを親プログラムに戻して、b(1),b(2),...,b(5) に入れたいのです。このとき、再びa() も必要になるので別名にする必要があるということです。

1次元配列や2次元配列の場合だったら、まず配列を一気に送って加工し、その配列 c(i,j) を一度Book を開いてデータを書き込み、サブプロシージャからそのbook名を返してこればやりたいことはできるのですが、最終的には3次元か4次元配列になりそうなので、それが面倒になりそうだからです。

もう一点、なぜサブプロシージャに送るかというと、今は親プログラム1本で非常に長いコードを書いてます。そのプログラムを友人に見せたところ「構造化プログラミングにしたほうがいいよ」と言われたからです。(私のつたない理解では、構造化プログラミングとは長いプログラムを、処理事にサブプログラムに分割してすっきりとしたプログラムにすることだと考えています。違ってるかもしれませんが・・・)

非常に長くなりましたが、趣旨はご理解いただけたでしょうか? まずはお答えいただいたプログラムを完全に理解するのが筋なのですが、取り急ぎお礼をしたかったため書き込みさせて頂いた次第です。明日ゆっくり勉強してみます。ありがとうございました m(__)m  (ろっしい)


  ろっしいさん、お勉強中でっか? だったらごめんなさい。
 いいええな、貴殿の問いに呻吟しとんのは私自身配列ちゅうもんがどんなもんかよう 理解でけてえしまへんさかい、一緒に勉強させてもろてまんねん。ですからお礼なん ぞ書かんとっておくんなはれや、ほんまに。
  こうやって恥ずかしくもなく稚拙なコードを書いときますと、有り難いことに り なさんみたいな熟達者がさっと間違いを指摘してくれまっしゃろ。勉強になりまんね んな、これがまた。
  で、また厚かましく、コードを書いときまっさ。動くことは確認済みですさかい時 間があったら試してみて下さい。(おいぼれ弥太郎)

     Dim n As Integer
    Dim hairetA(5) As Integer, hairetB(5) As Integer

  Sub 親プログラム()
    Dim i As Integer
   '便宜上hairetAに入力しときます。      
   For i = 1 To 5
        hairetA(i) = 5 * i
    Next
    ’Functionを実行させます。
  keisan (hairetBの必要時書き込み)
   ’ここからは確認のための作業ですから不要 
   For i = 1 To 5
        Cells(i, 1) = hairetB(i)
    Next i
    Cells(i - 1, 3) = hairetB(3)
 End Sub

Function keisan() As Integer
    For n = 1 To 5
        Select Case n
            Case 1
                keisan = hairetA(1) + hairetA(2)
            Case 2
                keisan = hairetA(1) + hairetA(4)
            Case 3
                keisan = hairetA(2) + hairetA(3)
            Case 4
                keisan = hairetA(3) + hairetA(4)
            Case 5
                keisan = hairetA(4) + hairetA(5)
        End Select
        hairetB(n) = keisan
     Next n
 End Function


 こんにちは

 >最終的には3次元か4次元配列になりそうなので、それが面倒になりそうだからです。

 Dim hairetsu(5,5,5,5) As Integer とすれば625個、
 Dim hairetsu(10,10,10,10) As Integer では10000個ものInteger型配列が
 定義されるとおもいますが、そこまでの多次元配列が必要ですか?

 おいぼれ弥太郎さん
 私が書こうとおもったらすでに書き込まれていたのですが、せっかく作ったし
 少し違うので一応書いておこうとおもったのです
 間違いを指摘したつもりではないので、もし気を悪くされたのならすいませんでした。
 ちなみに私も初心者ですよ (りな)

 Integer型配列 → Integer型変数 の間違い (りな)


 りなさんこんちわ

 いえいえ、気ぃ悪うするなんてとんでもおまへん。私の文面、気ぃ悪うしたみたいに
 見えたんやったらこっちこそごめんやで。
 それどころか、あぁそんなあるんやなあと早速コピー取っときましたわ。初心者にと っては何もかも勉強ですさかいな、ええ。
ところで3次元とか4次元とかの配列の話になるとコラもう私の能力の範囲外でして  何やらお門違いの所へ首突っ込んだようで慚愧の至りですわ、ええ。
 (気分こわしたんとちゃいまっせえ。念のため) おいぼれ弥太郎
 

 みんな頑張ってますね。
 勝手にロムろうと決めていたんですけど、ちょっとだけ参加〜

 hairetsuをファンクションプロシージャに参照で渡し、
 その戻り値をhairetsu_10に参照で戻すということで、
 Variant型で配列のアドレスを受けるのが簡単です。
 (ramrun)

 Sub macro()
    Dim hairetsu(1 To 10) As Integer
    Dim hairetsu_10 As Variant
    For i = 1 To 10
        hairetsu(i) = i
    Next i
    hairetsu_10 = fnc(hairetsu)
    For i = 1 To 10
        Cells(i, 1).Value = hairetsu(i)
        Cells(i, 2).Value = hairetsu_10(i)
    Next i
 End Sub

 Function fnc(ByRef hairetsu As Variant) As Variant
    Dim buf As Variant
    buf = hairetsu
    For i = 1 To 10
        buf(i) = buf(i) * 10
    Next i
    fnc = buf
 End Function

 Sub 親()
     Dim hairetsu(1 To 5, 1 To 2) As Integer
     Dim i As Integer, n As Integer
     For i = 1 To 5
         hairetsu(i, 1) = i
     Next i
     子 hairetsu

     For n = 1 To 2
         For i = 1 To 5
         Cells(i, n).Value = hairetsu(i, n)
         Next i
     Next n
 End Sub
 Sub 子(hairetsu)
     Dim j As Integer
     For j = 1 To 5
         hairetsu(j, 2) = hairetsu(j, 1) * 10
     Next j
 End Sub

 これではダメでしょうか? 

 >いえいえ、気ぃ悪うするなんてとんでもおまへん。私の文面、気ぃ悪うしたみたいに
 >見えたんやったらこっちこそごめんやで。
 ちょっと安心しました (りな)

 <ramrunさん>
 さすが手練れ者、あっさり極上のコードを作られてしまいましたなぁ。
 ByRefなんぞさわったこともおまへんから、早速コピーしてどんな働きをするのか黄色
 のマークを何遍廻したやら... 
 まだまだ理解でけてまへんが、見よう見まねで作り替えてみましたん。こんな使い方で
 どないでっしゃろか?
  いゃあ、ろっしいさんに適切な解答をつけるどころか、それに便乗してちゃっかり私
 の為の教室に変えてしもたみたいで、なんや悪いような儲けたような(間違いなく後者
 ,ろっしいさん御免)気がしますわ、ええ。
  ところで、つかぬ事をお伺いしますが、皆さんCells(a,b)の後に.Valueと書いてまん
 なあ。あれって必要なんでっしゃろか?気になりまんねん。
  1つの設問でこないに長いこと引っ張っとったらそのうちKazuさんにお小言ちょうだ
 いしそうでんなぁ。(おいぼれ弥太郎)(^^)


  Dim hairetsu(1 To 5, 1 To 2) As Integer

  Sub 親プログラム()
    Dim hairetsu_10 As Variant
    Dim i As Integer
   For i = 1 To 5
        hairetsu(i, 1) = i * 5
    Next
    x = True ' ここはセル参照するようにすればコードをいじらなくて済む
    hairetsu_10 = func(x, hairetsu)
    For n = 1 To 2
        For i = 1 To 5
            Cells(i, n).Value = hairetsu_10(i, n)
        Next i
    Next n

 End Sub
 ----
 Function func(ByVal x As Boolean, ByRef hairetsu As Variant) As Variant
    Dim y As Integer
    Dim buf As Variant
    If x = True Then
        y = 5
    Else
        y = 10
    End If
    buf = hairetsu
    For n = 1 To 5
        Select Case n
            Case 1
                buf(n, 2) = hairetsu(1, 1) + hairetsu(3, 1) * y
            Case 2
                buf(n, 2) = hairetsu(2, 1) + hairetsu(4, 1) * y
            Case 3
                buf(n, 2) = hairetsu(2, 1) + hairetsu(3, 1) + y
            Case 4
                buf(n, 2) = hairetsu(3, 1) + hairetsu(4, 1) + y
            Case 5
                buf(n, 2) = hairetsu(4, 1) + hairetsu(5, 1) + y * 2
        End Select
     Next n
     func = buf
 End Function

 >皆さんCells(a,b)の後に.Valueと書いてまんなあ。あれって必要なんでっしゃろか?気になりまんねん。
 わたしは .Valueを省略すると読みにくくなると思うんで省略しないんですよね
 あと、どっかのホームページにVBAでは省略しないほうが効率がいいみたいなこと書いてました。
 ByRefは参照渡しを明示するためでしょう (りな)

 そうですね、Cells(r,c).Value は入れるのが由緒正しいコードの書き方です。
 省略してもきちんと動きます。
 どちらにするかは、本人が決めればよいのです。
(kazu)


みなさん、本当にありがとうございました。色々勉強になりました。

まず、2次元配列や3次元配列が必要な背景は、現在仕事で会計上の項目が32個あって、その項目が12ヶ月分あり、さらに、部署ごとにシートになっていて、部署が4つあるデータを扱っていて、それが相互に関係する計算をする必要があって、それを一気に計算したいため、32×12×4 を組んでしまったのです。それが複数年度に渡る場合は4次元になりますが、いまのところは単年度ベースで良いみたいなので、3次元で収まっています(もっとスマートなやり方がありそうですが、なんか一気にやりたかったのです)。

さて、みなさんが書いてくださったコードを、一応自分でも一通りやってみて、最後に疑問が残ったことがあります。このままやっても問題なくプログラムは走るのですが、根本的に理解していないままやっていって、また同じような質問をするのは失礼かと思い、「聞くは一時の恥、聞かぬは一生の恥」と思い、一点だけ教えていただければ幸いです。

私は、以下のようなテストをしてみました。ByRef は今回初めて知ったのですが、ヘルプを参照したところ、ByVal の値渡しの方が、元々のデータを壊さなくて(私にとっては)ベターかなと思い、コードを書いてみました。

Sub macro()

    Dim hairetsu(1 To 10) As Integer
    Dim hairetsu_10 As Variant
    Dim hairetsu_20 As Variant

    For i = 1 To 10
        hairetsu(i) = i
    Next i
    hairetsu_10 = fnc(hairetsu)
    hairetsu_20 = fnc_2(hairetsu)

    For i = 1 To 10
        Cells(i, 1).Value = hairetsu(i)
        Cells(i, 2).Value = hairetsu_10(i)
    Next i

    For i = 1 To 10
        Cells(i, 3).Value = hairetsu_20(i)
    Next i

 End Sub

 'Function fnc(ByRef hairetsu As Variant) As Variant	'コメント化してあります
 Function fnc(ByVal hairetsu As Variant) As Variant

    Dim buf As Variant
    buf = hairetsu
    For i = 1 To 10
        buf(i) = buf(i) * 10
    Next i
    fnc = buf

 End Function

'Function fnc_2(ByRef hairetsu As Variant) As Variant 'コメント化してあります

Function fnc_2(ByVal hairetsu As Variant) As Variant

    'Dim buf As Variant			'コメント化してあります
    'buf = hairetsu			'コメント化してあります
    For i = 1 To 10
        'buf(i) = buf(i) * 10		'コメント化してあります
        hairetsu(i) = hairetsu(i) * 10      ' 自分なりに変えてみたところです
    Next i
    'fnc = buf				'コメント化してあります
    func = hairetsu 			' 自分なりに変えてみたところです
 End Function

fnc_2 で上手くいかないところが疑問点です。
私の理解では、fnc_2 に値渡しで送っているので、fnc_2 中の hairetsu は macro() 中の配列とは違ったもので、かつバリアント型なので動くかなぁと思ってやってみたのですが、やっぱり親プログラム macro() の中の hairetsu_20 に行った所で「型が一致しません」とエラーで止まりました。
何故、 buf のような他の配列に入れると上手くいって、そのままやってしまうと上手くいかないかが理解できずにいます。

質問ばっかりしていてお叱りを受けるかもしれませんが、これが解ると配列だけではなく、変数の型等の理解も深まると思い、恥を承知で最後のお願いにあがった次第です。よろしくお願いします m(__)m (ろっしい)


 >ろっしいさんこんばんわ
 コードの書き間違いとちがいまっか?Function fnc_2のコードの最下行func=hairetsu
 はfnc_2=hairetsuでないとあかんのんちゃいまっか。書き換えたら動きましたでぇ。

 >kazuさん、りなさん.Valueの件、早速のご返答おおきに。これからは私も由緒ある書
 きかたを身につけるよう心がけますわ。kazuさん怒ってはらへんみたいで良かった良
 かった。
  りなさん、アンタ初心者を名乗るんは止めてくれしまへんか。でないとほんまの初
 心者の立場がなくなりまんがな。(**)←これ怒った顔
    おいぼれ弥太郎 


間違えてました。お恥ずかしいです。穴があったら入りたいほどに・・・・・

ですが、こんなマヌケな質問にまで最後までお付き合いいただき、まことに感謝しています。
すべて解決してすっきりさわやかです。いろいろとありがとうございました。 m(__)m (ろっしい)


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.