assoc配列をhashにする
勉強がてら、Ruby1.9でassocArrayになっている配列からハッシュを作るメソッドをArrayに追加してみました。
自分は、主にテキスト処理(sar だの iostat だのの結果をマージしたり平均したり)をするのに
Ruby を使うことが多くて、単語分割して先頭をキーにしてごにょごにょということをよくやるんでこんなメソッドがあると便利かなと。
以下、svn diff
Index: array.c =================================================================== --- array.c (revision 15580) +++ array.c (working copy) @@ -2272,6 +2272,25 @@ return Qnil; } +VALUE +rb_ary_assoc_to_hash(VALUE ary) +{ + long i; + ID key_p; + VALUE v; + VALUE hash; + hash = rb_hash_new(); + key_p = rb_intern("key?"); + for (i = 0; i < RARRAY_LEN(ary); ++i) { + v = rb_check_array_type(RARRAY_PTR(ary)[i]); + if (NIL_P(v) || RARRAY_LEN(v) != 2 ) + return Qnil; + if (!(rb_funcall(hash,key_p,1,RARRAY_PTR(v)[0]))) + rb_hash_aset(hash, RARRAY_PTR(v)[0], RARRAY_PTR(v)[1]); + } + return hash; +} + /* * call-seq: * array.rassoc(obj) -> an_array or nil @@ -3278,6 +3297,7 @@ rb_define_method(rb_cArray, "slice!", rb_ary_slice_bang, -1); rb_define_method(rb_cArray, "assoc", rb_ary_assoc, 1); + rb_define_method(rb_cArray, "assoc_to_hash", rb_ary_assoc_to_hash, 0); rb_define_method(rb_cArray, "rassoc", rb_ary_rassoc, 1); rb_define_method(rb_cArray, "+", rb_ary_plus, 1);
以下、備忘録。
C から Ruby のメソッドを呼ぶ際は、rb_intern(str)で、ID を取得し、rb_funcall(resv,id,argc.arg1...)で実行できる。
以下、疑問。
C で Ruby のオブジェクトを取得して、その関数内でいらないって思っても、解放する術ってないんだよね?
で、上記パッチのために書いたテスト。一応、make test が動くことを確認するのは、エチケットかなって。(でも、最近の trunk のコード、テスト通らないんだよね。)
Index: test/ruby/test_array.rb =================================================================== --- test/ruby/test_array.rb (revision 15580) +++ test/ruby/test_array.rb (working copy) @@ -423,6 +423,24 @@ assert_equal(nil, a.assoc(1..2)) end + def test_assoc_to_hash + a1 = @cls[*%w( cat feline )] + a2 = @cls[*%w( dog canine )] + a3 = @cls[*%w( mule asinine )] + a4 = @cls[*%w( cat asinine )] + + a = @cls[ a1, a2, a3, a4 ] + hash = a.assoc_to_hash + + assert_equal(['cat',hash['cat']], a.assoc('cat')) + assert_equal(['cat',hash['cat']], %w[ cat feline ]) + assert_equal(['mule',hash['mule']], a.assoc('mule')) + assert_equal(hash['asinine'], a.assoc('asinine')) + + assert_equal(nil,%w( cat feline dog canine ).assoc_to_hash) + assert_equal(nil,[%w( cat dog rabbit),%w(car ship plane)]) + end + def test_at a = @cls[*(0..99).to_a] assert_equal(0, a.at(0))
以下、感想。
この程度の処理なら思ったより簡単にでけた。たぶん、1.9 のみの関数を呼んでいないはずなので、1.8 でもだいじょうぶかなと思っている。
次のステップとしては、イテレーターを扱うメソッドを作ってみたいと思う。