blog.waterlow.work

Ruby, Rails, js, etc...

Effective Rubyを読んで気になったこと(reduce・each_with_object・inject)

途中までですが、Effective Rubyを読んでみました。

Effective Ruby

Effective Ruby

「項目19 reduceを使ってコレクションを畳み込む方法を身に付けよう」を読んだとき、まず恥ずかしながらreduceというメソッドを知らなかったです。injectは知っていたのですが、そのエイリアスだそうです。

injectreduce)と聞くと、自分ならeach_with_objectを使うかなと思いました。細かいですがinjectだとアキュムレータを返す必要があるからです。 こんなかんじです。

[1, 2, 3, 4].inject([]) do |nums, num|
  nums << num * 2
  nums
end

each_with_objectだと副作用的に更新していってくれるのでその必要はありません。

[1, 2, 3, 4].each_with_object([]) do |num, nums|
  nums << num * 2
end

視点を変えてみる

そもそもinjectreduceには発想の違いがあるようです。(非常にわかりやすい図とともに説明されています。 Rubyist Magazine map と collect、reduce と inject ―― 名前の違いに見る発想の違い

reduceを使うということは、「このコレクションの畳み込みをします。」というのをメソッドで自己ドキュメント的に宣言できるということです。(最低現reduceの単語の意味は知っておく必要がありますが…。)それに対しeach_with_objectは「コレクションのループと同時にこのobjectを更新していきましょう」ということしか読み取れません。畳み込む場合は、多少記述が増えてもreduceを使うのがいい気がしました。

結論

畳み込みする(要素を足しあわせたり、条件に応じて捨てたりする)ときはreduce、そうでなく、例えばオブジェクトのArrayからHashに変換するみたいな場合はeach_with_objectを使うのがよさそう。injectはどうしよう><