Ruby の each_with_object と inject について
each_with_object とは
each_with_object を使用すると、配列やハッシュの要素を使って、
新たに配列やハッシュを作成したりする際に、簡潔に書くことができます。
簡単な例を以下に示します
array = [[:hoge, 1], [:fuga, 2], [:piyo, 3]] array.each_with_object({}) do | (key, value), hash | hash[key] = value end # => {:hoge=>1, :fuga=>2, :piyo=>3}
inject とは
inject は each_with_object と一見似ていますが、
返り値等の振る舞いが微妙に異なります。
先ほどと同じ振る舞いをinjectを使って実現すると。
array = [[:hoge, 1], [:fuga, 2], [:piyo, 3]] hash = array.inject({}) do | hash, (key, value) | hash[key] = value hash end p array # => [[:hoge, 1], [:fuga, 2], [:piyo, 3]] p hash # => {:hoge=>1, :fuga=>2, :piyo=>3}
まず、each_with_object が破壊的メソッドであるのに対し
injectは破壊的ではないことがわかります。
さらに、
- each_with_object では 引数に渡されたオブジェクトが常にhash変数に入っていますが
- inject ではブロック内で最後に評価された値が入ります
そのため、injectで同じ挙動を再現したかったら最後に hash の一行を余計に書く必要が出てきます。
inject の使い所は?
配列やハッシュの要素から一つのオブジェクトを作る場合は injectがとても便利です。
sum = 0 (0..10).each { |i| sum += i } p sum # => 55
こんなコードを
(0..10).inject(0) { |sum, i| sum + i } # => 55
こんな感じに簡潔にすることができます。
さらに
(0..10).inject(:+) # => 55
こんな風にもっとスマートに書くこともできます。
こちらもどうぞ