「hashMap」メソッド

jijixi's diary - 関数型脳になると、ちょっとイラっとする Ruby の要素 , ActiveSupport::OrderedHash に絶望したで、

例えば、あるハッシュをいじって別のハッシュを作りたいときがある。 関数型脳なんだから、当然のように元のハッシュを書き換えるんじゃなく、新たなハッシュを作りたい。
ここで、手続き型脳で考えた場合、話は簡単だ。

irb(main):001:0> a = { :hoge => 1, :fuga => 2, :piyo => 3 }
=> {:hoge=>1, :fuga=>2, :piyo=>3}
    irb(main):002:0> b = {}
    => {}
    irb(main):003:0> a.each do |k,v|
    irb(main):004:1*   b[k] = v + 1
    irb(main):005:1> end
    => {:hoge=>1, :fuga=>2, :piyo=>3}

こう書けば良い。 でも、関数型脳で考えると、こういうシチュエーションはどうしても map を使いたくなる。

から始まって、つらつらとRubyじゃ出来ないよー、と嘆いてるを見て、

なんかこの「ハッシュをかえすハッシュ.map」て、欲しかったら動的メソッド足せばええやん、とか思った。適当な名前で…「hashMap()」?

とかtwitterで言ってしまったので書いてみました。
要は、

assert [a:1, b:2, c:3].hashMap{it*2} == [a:2, b:4, c:6]

が出来ればうれしいんでしょ?ということで出来るようにしました。

LinkedHashMap.metaClass.hashMap = {clos->
    def res = [:]
    delegate.each {key, value->res[key] = clos(value)}
    return res
}

assert [a:1, b:2, c:3].hashMap{it*2} == [a:2, b:4, c:6]

…中身はまんまやん!

もうちょっとかっこ良く書きたいなぁ…ということで、第二弾。

LinkedHashMap.metaClass.hashMap = {clos->
    delegate.collect{[(it.key):clos(it.value)]}.sum()
}

assert [a:1, b:2, c:3].hashMap{it*2} == [a:2, b:4, c:6]

いちおう関数型ぽい?
…しかし重そう、と思ってちょっと計ってみたら、2.4GHz Core 2 Duoの乗ったMac上のJava6:groovy1.6で10000件のMapのhashMap{it*2}に4秒かかりましたw