LoginSignup
148
117

More than 5 years have passed since last update.

injectとeach_with_objectって何が違うのさ?

Last updated at Posted at 2014-09-08

injecteach_with_objectの違いが分からない。
どちらもEnumerableなオブジェクトの要素を使って何かしらのオブジェクトを得る。

でもやっぱり違いがあったのでメモ。

イメージで説明

  • injectは、各要素が力を合わせて一つのオブジェクトを作る
  • each_with_objectは、ターゲットとなるオブジェクトに対して、各要素を作用させる

挙動で説明

配列の各要素を2乗する処理を書く。表面上は同じ挙動をする。
でもdoの後のresultは、同じresultでも意味合いが違っていて、

  • injectの場合はresultにはブロック内で最後に評価した値が入る
  • each_with_objectの場合は、resultは常にeach_with_objectの引数として渡されたオブジェクトを指す
hoge.rb
# inject
[1, 2, 3].inject [] do |result, i|
  result << i*i
end

# each_with_object
[1, 2, 3].each_with_object [] do |i, result|
  result << i*i
end

injectを使いたい場合の例

たとえば配列の和を求める場合

hoge.rb
sum = [1, 2, 3].inject 0 do |s, i|
  s + i
end

(この場合はsum = [ 1, 2, 3].inject :+でいいけど敢えてこの形で。)

ここでeach_with_objectを使おうとしてしまうと、

hoge.rb
sum = [ 1, 2, 3].each_with_object 0 do |i, s|
  s += i
end

とすればよさげだけど、sは破壊的に変更できない0(Fixnum)を指しているので、
sumに入るのは0となってしまう。

each_with_objectを使いたい場合の例

たとえば[["Alice", 50], ["Bob", 40], ["Charlie", 70]]から、{"Alice" => 50, "Bob" => 40, "Charlie" => 70}を得たい場合、

hoge.rb
ret = [["Alice", 50], ["Bob", 40], ["Charlie", 70]].each_with_object({}) do |(key, value), hash|
  hash[key] = value
end

こんな感じでかける。

ここでinjectを使おうとすると、できないわけではないけど、
作成中のハッシュをブロックの最後に評価しないといけないので1行余分に必要になる。

hoge.rb
ret = [["Alice", 50], ["Bob", 40], ["Charlie", 70]].inject({}) do |hash, (key, value)|
  hash[key] = value
  hash    # ブロックの最後の評価を作成中のハッシュにしないといけない
end

参考:
プログラミングは素晴らしい - [プログラミング] each、each_with_object、inject、map

148
117
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
148
117