Enumeration#inject

少し前までよく分かってなかったinjectメソッド。やっと使い方が分かってきました。
例えばあるオブジェクトの配列があったとして、その属性などからHashを作りたい場合、injectを使わない場合はこんな感じ。

irb(main):001:0> rows = [{:id => 1, :name => 'A'}, {:id => 2, :name => 'B'}, {:id => 3, :name => 'C'}]
=> [{:name=>"A", :id=>1}, {:name=>"B", :id=>2}, {:name=>"C", :id=>3}]
irb(main):002:0> dest = {}
=> {}
irb(main):003:0> rows.each{|row| dest[ row[:id] ] =row[:name] }
=> [{:name=>"A", :id=>1}, {:name=>"B", :id=>2}, {:name=>"C", :id=>3}]
irb(main):004:0> dest
=> {1=>"A", 2=>"B", 3=>"C"}


injectを使うとこんな感じ

irb(main):001:0> rows = [{:id => 1, :name => 'A'}, {:id => 2, :name => 'B'}, {:id => 3, :name => 'C'}]
=> [{:name=>"A", :id=>1}, {:name=>"B", :id=>2}, {:name=>"C", :id=>3}]
irb(main):002:0> rows.inject({}){|dest, row| dest[ row[:id] ] =row[:name]; dest }
=> {1=>"A", 2=>"B", 3=>"C"}

キモはinjectに渡されるブロックの戻り値となっているdest。injectメソッドはブロックの戻り値を次の要素のdestとして渡すんです。で、最初のdestの値はっていうとinjectの引数で指定するわけです。なので、例えばrowsに含まれていないものをdestに入れたい場合はこう書けます。

irb(main):001:0> rows = [{:id => 1, :name => 'A'}, {:id => 2, :name => 'B'}, {:id => 3, :name => 'C'}]
=> [{:name=>"A", :id=>1}, {:name=>"B", :id=>2}, {:name=>"C", :id=>3}]
irb(main):002:0> rows.inject({9=>'Z'}){|dest, row| dest[ row[:id] ] =row[:name]; dest }
=> {1=>"A", 2=>"B", 3=>"C", 9=>"Z"}

リファレンスにはちゃんと書いてあるんですよね。でも慣れないと難しいっす。
http://www.ruby-lang.org/ja/man/?cmd=view;name=Enumerable