VBAのメモ

ここ一ヶ月ほど業務でExcelマクロを組んでいて、VBAを触る必要があった。
VBAについてはしっかりと勉強をした事がなかったのだけど、触っていてハマったポイントなんかを書き留めておく。


論理演算子は必ず両辺を評価する

AndやOr演算子は左辺で条件が確定しても両辺を評価するようだ。

Sub test()
    If isA Or isB Then
        Debug.Print "true"
    Else
        Debug.Print "false"
    End If
End Sub

Function isA() As Boolean
    Debug.Print "A"
    isA = True
End Function

Function isB() As Boolean
    Debug.Print "B"
    isB = False
End Function

例えば上記のコードだと、Javaなどで考えると isA がTrueの場合、isBは評価せずにIf文の条件式は「真」となり実行されるが、VBAで実行してみると出力結果は

A
B
true

と表示されて両辺が評価されている事がわかる。


逆の And の場合も同様で左辺が False でも両辺を評価する。
なので And で2つの重めの処理の評価結果で分岐したい場合は、きっちりと分けて書かないと無駄に重たい処理を実行する事になる。

If isA Then '重めの評価
    If isB Then '二つ目の重めの評価。この場合、isAがFalseならisBは評価されない
        Debug.Print "true"
    End If
End If

また類似の処理ではVB版3項演算子 IIfの場合もそう。

    hoge = IIF(isA, getFoo, getBar)

この場合、isAの結果によらず getFoo, getBar が共に評価される。


getFoo, getBar が重たい処理の場合、面倒でも

If isA Then
    hoge = getFoo
Else
    hoge = getBar
End If

と書く必要がある。
まぁこれはVBAの関数が先行評価型である事を考えれば、当然なんだけど。三項演算子とは呼ばない方が良い気がする。


Private変数のスコープはプロシージャ内

プロシージャ内で宣言した変数はプロシージャ内であれば、どこからでも参照できる。For文の内側で宣言してFor文の外側からアクセスできる。つまり以下も問題なく動く

Sub test()
    For i = 0 To 5
        Dim a as String 'For文内でプライベート変数を宣言
        a = "hoge"
    Next

    Debug.Print a
End Sub

まぁこれはJavaScriptあたりと同様だ。


但し、JavaScriptみたいに以下のようには書けない。

Sub test()
    Debug.Print a '宣言前に参照
    For i = 0 To 5
        Dim a as String
        a = "hoge"
    Next
End Sub

For文内での変数宣言前に参照すると、その時に変数に値がバインドされて、For文内では2重宣言と見做されてしまうようだ。


そして少しハマったのが以下のケース。

Sub test()
    For i = 0 To 5
        Dim col as New Collection
        col.add i
    Next

    Debug.Print col.Count
End Sub

上記を実行すると6と表示される。
VBAの参照型変数は宣言時にNewを付けてオブジェクトの生成を行えるが For文内で書いた場合、最初の一回目でオブジェクトが生成されて2回目からは生成済みのものを使うよう。
なので上記の場合はコレクションに値を6回追加する事になる。


For文でループ毎にオブジェクトの生成を行いたい場合はSet を使って明示的に生成する必要がある。

Sub test()
    For i = 0 To 5
        Dim col as Collection
        Set col = New collection
        col.add i
    Next
    Debug.Print col.Count '1と表示される
End Sub

配列はindexが0から、コレクションは1から始まる

思わず、え??と聞き返しそうになるが。。。

Sub in_Collection_Case()
    Dim col as New Collection
    col.add "hoge"
    col.add "foo"
    ' コレクションの場合、indexは1から始まる
    For i = 1 To 2
        Debug.Print col(i)
    Next
End Sub

Sub in_Array_Case()
    ary = Array("hoge", "foo")
    ' 配列の場合は0始まり
    For i = 0 To 1
        Debug.Print col(i)
    Next
End Sub


まぁ実際は配列の場合でも

Sub in_Array_Case()
    Dim ary(1 To 2) As String
    ary(1) = "hoge"
    ary(2) = "foo"
    For i = 1 To 2
        Debug.Print ary(i)
    Next
End Sub

として1始まりで使うんだけど。


Arrayが0からって仕様が凄く不思議。




いろいろと厄介な仕様だったり、デバッガは使いにくいし、型を指定してるのに実行時まで型違いのエラーを
見つけてくれなかったりとイライラする事も多いけど、結構いろいろな事ができるので頑張ればvbaマクロだけでそこそこのシステムを作れそうな気がする。

非同期でHTTP通信とかもできるんだろうか。

Kanasan.JS JavaScript第5版読書会#8に行ってきた


今週の日曜にKanasan.JS JavaScript第5版読書会に参加してきました。
気づけばもう8回目。今回の範囲は443P〜477P。内容はほとんどHTMLの学習に近かったです。
特にIEに悩まされることなく平穏に学習は進みました。


今回はKanasan.js始まって以来、初めての京都開催でお結び庵という町家で開催されました。風情があってなかなか良かったです。子供の頃に田舎に帰った時の雰囲気を思い出しました。父親とかはああいった雰囲気の中で勉強してたのでしょうね。クーラーがないので少し暑かったですが。


勉強会自体は軽めの内容だったのでほどほどに、その後は同会場でそのまま懇親会に突入。
エディタやバージョン管理なんかの宗教論争的な争いがいろんな所で行われていました。
内容はマニアックだけどKanasan.JSは若い参加者が多いせいか熱いです。



さて次回はクライアント側のCookieを使ったデータ永続化とHTTPリクエスト周りについてです。
このあたりは今まであまりしっかりと学習してこなかったので次を機会にきっちりフォローしたいところです。

GTUG Android Hackathonに行ってきた


もの凄く久しぶりのblog更新。
勉強会への参加をきっかけに始めたこのブログだが、前回のエントリから実に2ヶ月近く更新がなかった。
これまで勉強会等への参加の際は大体Blogの更新をしていた。


つまり勉強会の参加自体があまりなかったという事の表れ。
もうちょっとがんばらないといけないな。



昨日、京都GTUG(Google Technology User Group)主催のAndroid Hackathonに参加してきた。
事前に勉強会2回とミーティング1回で4回目の参加。


事前ミーティングで参加者をいくつかのチームに分け、当日チーム毎にandroidアプリを作るというイベントだ。
私の入ったチームはGeoLocationチームというところで、GPS情報を使った何かを作るというチーム。


事前ミーティングの際に決まったアプリの内容はこう。


「移動中のロケーション情報を元に様々な情報を取得しそれを一覧やGoogleMap上に表示する。」


様々な情報というのは例えば、位置情報に関連づいた写真やコメント等。
それらをあたかもメールを受信するかのようにリストに溜めていく事ができ、あとで移動経路上にあったいろんな情報を見て楽しめるというもの。


今回は時間も限られているので取得する内容はFlickrAPIを利用しての写真に絞る事にした。
当日は誰が何を作るかなどの担当分けはせず、とりあえず各自が思い思いに作ってみてあとで何とかしようというノリでやってみることに。
結果、案の定というか当然ながら各自が作っている箇所が被りまくり。
中には3人で同じ箇所を作ったりしていた。


まぁ何かを完成させて表彰されたいというより、新しい技術に触れていろんな事をしてみるのが楽しいというのもあったのでそれぞれ自由にできて良かったのかもしれない。
もちろん結果は何の賞もとれなければ、最後の発表も準備をほとんどしてないのでグダグダなのは言うまでもない。
間違いなく今回のHackathonで一番纏まりが無いチームだったと思う。


それでも後の懇親会ではチームのメンバと技術の話で盛り上がり、楽しい時間を過ごしました。
皆さん技術が本当に好きなようでいい刺激をたくさん受けました。



ところで開発したアプリの方はというと未完には終わったものの、私はandroidから現在のGPSの変更イベントを受け取りFlickrGPS情報を送り、写真の一覧を受け取りリストに表示するというところまで作成できました。


いろいろ調べながらの為思いの他、時間はかかりましたが一番の嵌りどころはAndroidマニフェストパーミッションの設定を記述するところ。
GPSを使う為にはAndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

の記述を。
インターネットにアクセスする為には

<uses-permission android:name="android.permission.INTERNET"/>

の記述をする必要があります。


しかもこのパーミッションの設定は実行時にエラーを返すわけではなく、アプリの起動が出来なくなるだけでなくそのエラー内容も吐いてくれません。


その為、プリントデバッグでどこまで走ったかを突き止めようとしたのですが、対象のクラスがロードされた時点でエラーとなるので、例えGPS情報を取得するコードの呼び出し部分をコメントアウトしてもエラーとなりその内容が不可解なので無駄に
ログ出力処理埋め込み → 実行
を繰り返し時間を浪費しまくりました。

せめて「パーミッション」が無いなどのエラー内容を表示して欲しいところですね。


次回のGTUGのhackathonは話題の「Google Wave」になるだろうとの事です。
予定が合えば是非参加したいと思います。


参加者の皆様お疲れさまでした。
また主催して頂いたスタッフの皆様、心よりお礼を申し上げます。

WEBサービス「コレデター」を公開

えらく長い間更新してなかったけど、久しぶりの更新です。
ここのところプライベートでWEBサービスを作ってまして、
それを最近公開しました。


紹介

サービス名は『コレデター』。


コンセプトは「新しい物好きの為の新商品共有サイト」で、
ターゲットはこんな人達です。

  • コンビニで新しいお菓子が出てたらとりあえず買ってしまう
  • 新しいマックグルメは欠かさず食べにいく
  • ゲームは発売後すぐにやりたい
  • とにかく新しいものに目がない

などなど。

どんな事ができるの?

自分や誰かによって登録された商品をレビューしたり、
自分だけのオリジナルコレクションに加えて整理する事ができるので、
その新商品を試したかどうかを管理できます。


商品の登録・再編集にユーザー登録は不要。
レビューやコレクションにはユーザー登録が必要になりますが、
OpenIDも利用できるので気楽に試せるかな?

今後の方向

今後は携帯向けの機能を充実させていく事で、学校帰りの学生さんとかが
立ち寄ったコンビニで新商品を選びその場で登録、管理するといった
使い方に発展させていきたいなと考えております。


システムとか

バックエンドはRailsで動いています。
APIを用意しようとは特に思ってませんが
URLはなるべくRESTfulになるよう意識しました。


「koredeta」でtwitterアカウントを取ってますが、まだ何もしてません。
今後はダイジェストとかを流していこうかなって思ってます。


コレデターへは以下よりアクセスできます。
http://koredeta.com/


久しぶりにWEBサービスを作ってみたけど結構楽しかったなぁ。

Ubuntuを9.04にアップグレード

Ubuntu9.04 jauntyがリリースされてからしばらく経って、そろそろ情報も出てきたのでアップグレードする事にした。
環境はThinkpad X60でUbuntu8.10が入っている。
アップデートマネージャよりパッケージを最新状態にし、「9.04へアップグレード」ボタンを押す。


時間は1時間ちょっと要したが特に問題無く終了。
途中でmysqlとsambaの設定ファイルの更新について聞かれたが、元の設定ファイルを待避して共に最新化。


日本語入力にATOKを使っているので、アップグレードの最後のクリーンアップで不要パッケージの削除は「そのまま」を選ぶ。
これをしないとATOKが削除されてアプリが起動しなくなり、ATOKの再セットアップが必要だったりと面倒臭い事になるようだ。


8.04から8.10にアップグレードした時はネットワークとかいろいろ問題が起きたが、今回は全然問題も起こらず快適そのもの。



・・・のはずだった。


アップグレード後、システム>システム管理>不要パッケージの削除
を選んでクリーンアップ時に削除できなかったパッケージの削除を試みる。
ズラリと表示された不要パッケージの中から以下のパッケージを除外。

  • atokx
  • iiimf-gtk
  • iiimf-x

多分消すと面倒臭そうな気がする。


それ以外はまとめて削除。
すると更に1回目に表示されてなかったパッケージが不要パッケージとして表示された。多分1回目消したパッケージが依存していたものだろう。
中にはAnthyなんかも含まれていたように見えたが気にせず全削除。
マシンを再起動してみると、、、何か変だ。
全てのメニューが英語になっている??


FireFoxを立ち上げて調べようとするも日本語入力すらできない。。。
ここで少し後悔しそうになったが、とりあえずVirtualBoxを起動して、仮想マシンWindowsを動かしてみた。すると普通に日本語が入力ができる。
これで調べることできる。


どうやら日本語パッケージをまとめて削除してしまっていたみたい。
Synapticを立ち上げ以下のパッケージとその依存するパッケージをインストール。

  • language-support-ja
  • language-pack-ja
  • language-pack-gnome-ja


再起動すると無事元の環境に戻りました。
しかも不要パッケージも整理できて結果的にむしろ良かったかも。


アプリの設定類もそのまま引き継がれている。テーマですら。
感覚的に何か変わったというほど何も変わってないような気がするが、ネットワークの接続が早くなったかな?
あとメッセージのアラート表示が綺麗になったのは良い。

Haskellで組み合わせ

Haskellを使ってリストの中から任意の要素数の組み合わせをとる処理を考える。

2要素の場合

とりあえず2要素の場合はなんとなく感覚的に出来た。

--combはcombinationの意
comb [] = []
comb (x:xs)=[[x,y]| y <- xs] ++ comb xs

main=do print $ comb [1..4]
-- > [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]

n要素の場合

任意の要素を取り出す場合の処理になると急にややこしくなる。
要素5個のリストから3つを取り出す組み合わせのツリーを考えると以下の様になる。

--------------------
1-2-3
   -4
   -5
 -3-4
   -5
 -4-5
--------------------
2-3-4
   -5
 -4-5
--------------------
3-4-5

図になってない為分かりにくいが破線(----) 毎に横向けのツリーだと思う事にする。
空白の列は上と同じという事。(やっぱ後で図にしようか。。。)


各ツリーのルート要素(上の場合1と2と3)が元々のリストの要素数に応じて再帰的に増えていき最終的に結合する事になる。
なので2要素を取り出す場合と同じように
[一つのツリーを表すリスト] ++ [再帰で別のツリーを表すリスト]
という構造になるはず。


次に一つのツリーに着目すると取り出す要素の数nに応じて、上の図で列の部分(ツリーの深さ)が再帰的に増えるのでこの部分をどうするかがポイント。
深さ4のツリーだとルート要素を除いた時、その下に深さ3のツリーがある事がわかる。同様にその深さのツリーのルート要素を除くと、その下に深さ2のツリーがある事がわかる。この部分を再帰で表現すればいけそう??

そうしてできた処理が以下。

--combn は n要素の combinationの意
combn [] n=[]
combn lst 1=map (\x -> [x]) lst
combn (x:xs) n=[x:y| y <- combn xs (n-1)] ++ combn xs n

main=do print $ combn [1..5] 3
-- > [[1,2,3],[1,2,4],[1,2,5],[1,3,4],[1,3,5],[1,4,5],[2,3,4],[2,3,5],[2,4,5],[3,4,5]]

おおエレガント!haskellで考えると無駄なく書ける。

手続き的に考えた場合

JavaScriptを使って手続き的な処理でも書いてみた。

function comb(lst, k) {
    var tmp = [];
    for(var i = 0; i < k; i++) tmp[i] = i;

    var res = [tmp];
    while(true){
	tmp = inc(tmp, lst.length-1);
	if(tmp) {
	    if(uniqueness(tmp)) res.push(tmp);	    
	} else {
	    break;
	}
    }
    
    for(var i in res) {
	for(var j in res[i])
	    res[i][j] = lst[res[i][j]];
    }
    return res;
}

// [0,1,2] を受け取ると [0,1,3] を返す。値をインクリメント。
function inc(lst, max) {
    var res = [];
    for(var i = 0; i < lst.length; i++) res[i] = lst[i];

    for(var i = res.length - 1; i != 0 ; i--) {
	if(res[i] + 1 <= max) {
            res[i]++;
            return res;
        } else if (i > 0){
            res[i] = res[i-1] + 2;
            if(res[i] > max) break;
        }
    }
}

function uniqueness(lst) {
    var tmp = [];
    for(var i = 0; i < lst.length; i++)
        tmp[lst[i]] = (tmp[lst[i]] || 0) + 1;

    for(var j = 0; j < tmp.length; j++)
	if(tmp[j] > 1) return false;

    return true;
}

var ary = ["a","b","c","d","e"];
print(comb(ary,3));
// ->  [["a","b","c"],["a","b","d"], ["a","b","e"], ["a","c","d"], ["a","c","e"], ["a","d","e"]]

別に無駄に長くしようとしたわけではなくて、もっとちゃんとしたアルゴリズムを使ってやれば短くできるんだろうけど。

まぁhaskellで書いたのと同様に再帰で書けばいいだけなんだけど、再帰を考えるときhaskellは非常に相性がいい。

SVC関西帰国報告会に行ってきた

SVC帰国後、関西組で公式には初の顔合わせとなる帰国報告会が京都西陣町屋スタジオで開催されたので行ってきた。


久しぶりに旅行中に一緒だったメンバーと会い、それぞれの今の心境や活動報告をしながら飲んで食べて懇親を深めるという会だ。
SVCに参加したメンバー以外にも今年行こうと思っていけなかった人、来年行く予定の人、興味のある人達なんかも参加されていたようだ。


id:hxmasaki,id:satzzによる旅行中に撮りためた写真の鑑賞会、id:ninjinkunによるLT、参加者が展開されているWEBサービスの紹介などがあった。私も僭越ながらすうじあむの紹介をさせてもらいました。


中には既にシリコンバレーで起業されているrakusaiさんも居て、いろいろと興味深い話をさせて頂きました。ビザの関係でたまたまこっちに戻ってこられていたそうです。主なプロダクトにはNOTA紙copi等があるそうです。



SVCの参加者にはSVC参加後、留学を決意して既に行動を始めている方もちらほら居たりして、話を聞くだけでいい刺激になりました。
また機会があれば是非とも集まりたいですね。幹事のid:satzzありがとうございました。参加された皆さんお疲れ様でした。