2004年10月07日 木曜日

Excel VBAは究極の「変数 = 箱」モデル

某MLに書いた内容ですが、僕が遭遇したExcelVBA的なものの発想法について。
ExcelVBAでのプログラミングでは、8月8日の日記福盛さんの日記で触れられているように、「VBAでエクセルのマクロを作る初心者がですね、変数の代わりにセルを使うんですよ」と言うような、matz日記で話題になった究極の「変数 = 箱モデル」に相当するようなコードを書く人が結構多い。
つまり、「ExcelVBAは普通のVBと違って、「手動で」かつ「視覚的に」変数領域を割り当 てられる、2次元でアドレス指定するポインタを持つBASICである。」と言い換えても良さそうですし、暴論を言えば、「一流のExcelVBA使いは1次元のポインタしかないCのポインタなど目をつぶって使えないとならない訳だ(暴論)。分からないなどと言わせぬ!」ということになる。まぁ実際に一流の(分かった気になって、有頂天になって、ナニか勘違いしている人_のことを言う)ExcelVBA使いのみなさんはこういうポインタに相当するものには名前をつけたりしなくて「全部直接セル参照」という神業をするので、構造化言語とかOOPとかにジャブ付けの頭しか持ち得ない僕なんかから見るとある意味「すげーっ!」(絶対そうなりたくない)と思ったり、頭の中がどうなっているのかかち割って見てみたいなんて思っている_3流のへっぽこVBA使い_なので、せめて妥協点として、Rangeオブジェ クトに名前をつけてアクセスしたくなっちゃいます。
1次元のRange領域を作ってやれば普通のポインタと同じような感覚(アドレス指定はCellsプロパティで2次元指定できるけど)ですかね。領域の割り当ては自分でやらないと駄目ですが… まぁ_ご利用は計画的に

たとえば「1から10までの話を求めたい」と言う例題を考える。和を求めたいRangeオブジェクトを渡すと「Rangeの和を求めるワークシート関数を文字列として返す関数」なんてものをつくってやれば、少し楽ができそうし、応用もあるのは手を付けてはいけないと思いますねえかな? まぁ実際にこつこつアルゴリズムを書くのではなく、計算などはすでにあるExcelのワークシート関数にしまえと言うことになります。(まぁ_手抜き_とも言う) 和を求めるくらいだとあまりありがたみが出ないが、同じ手間でRangeの最大・最小とか2個のRangeオブジェクトを関数に渡して最小自乗法とかさくっと出来ちゃったりするので、まぁ楽チンですね。(実際は統計関係の計算をするときはExcelのバグを知り尽くしてないと危ないですが。まぁ統計をちゃんとしたい時はExcelは使っちゃいけません。ちゃんと統計ソフトを使いましょう。)
ということでコード例。(基本的にVBでプログラムを書くときは型宣言を必須にしましょう。そうでないと全部Variantになったりしますから。あとDim文の使い方も意図しない型宣言になったりしますので注意しましょう。)

Option Explicit 
Sub test()
    Dim n As Integer
    Dim i As Integer
    Dim list As Range
    Dim Sum As Range
    
    n = 10
    
    '変数領域の割り当て
    Set list = Range(Cells(1, 1), Cells(n, 1))
    Set Sum = Range(Cells(1, 2), Cells(1, 2))
    
    For i = 1 To n
        list.Cells(i, 1).Value = i
    Next
    
    Sum.Formula = accumulate(list)
    
    MsgBox ("1から" & n & "までの和は" & Sum.Value & "です。")
End Sub
Public Function accumulate(list As Range) As String
    accumulate = "=sum(" & list.Address & ")"
End Function

あとセルとワークシート関数を使えば連想配列もどきなんかも「視覚的」に…(データ構造とか検索する時間とか計算量とかアルゴリズムとかを考えるなんてVBA使いには無粋ということで。)
ちなみに僕のVBAのコーディングはVBとのポータビリティも考えて書いているので、Excelのオブジェクトを生成して適当にソースを書き足せば、だいたいそのまま移植できます。こういうプログラムは今回初めてしてみました。まぁ世の中視覚的に表現できないデータはサクサク想像できる(たとえば4階のテンソルとか)ので、こういう視覚的なやり方に頼ったことはあまり考えちゃいけません。ちゃんと訓練しましょう。

久しぶりに地震

久しぶりというのが何とも言えないのだが、震度4程度の結構激しい地震があった。夜11時半過ぎで半分寝ていたのだが、意識朦朧ながらめが冷める。とりあえず大きな被害は無し。家に帰る途中とか夕方とかじゃなかったのが、不幸中の幸いか。夕方だったらこんな地震でも大規模火災になりそうな気はするので。みなさん注意しましょう。(それにしても_たいしたこと無いな_と言う見切りが早すぎだな…)