Ruby: .each_with_object or .inject?

Ruby: .each_with_object or .inject?

Image for post

Ruby Rouges is one of my favorite programming podcasts. I recently stumbled upon a code review video that they recorded about two years ago. The video is a code review of the dotenv gem and gave me an inside peak of the process that a couple of experienced and knowledgeable Ruby programmers use to step through an unknown codebase.

I highly recommend this video to all Ruby programmers because I think it is full of interesting discussions and information. The one discussion that sparked the topic for this article is about using the inject method instead of the each_with_object method. The discussion begins about 21 minutes into the recording. Before this video, I had never given any thought about the differences between the two methods. In order to form my own opinion I decided to compare the two methods myself.

The Inject Method

The official Ruby documentation defines inject as:

Combines all elements of enum by applying a binary operation, specified by a block or a symbol that names a method or operator.

The most important thing to understand about inject is that as you loop through each element of your enumerable object, a second accumulator value is passed in as well. The accumulator value is updated on each iteration and eventually returned.

I have pretty much only used the inject method to perform a mathematical operation on an array of numbers. For example:

(1..5).inject(0){ |sum, num| sum + num } ==> returns 15

This example simply keeps track of a sum variable and adds each number in the array to it and then returns the sum at the end.

You can also use inject to convert an array into a hash. The following is a code example I borrowed from Chris Mar?s blog post

Image for post

In this second example, there are a couple of key things to notice:

  1. We are passing in an empty hash as the initial value for our accumulator.
  2. We are calling the merge method on our accumulator hash each iteration. This method returns an updated hash as our new accumulator.

The Each_With_Object Method

The official Ruby documentation defines each_with_object as:

Iterates the given block for each element with an arbitrary object given, and returns the initially given object

Using the same code example above, we can use each_with_object to convert an array into a hash:

Image for post

There are a couple of important differences to notice about the code above and the inject example:

  1. The arguments are reversed. In inject, the order of the arguments are |accumulator, element| but in each_with_object the order of the arguments are |element, accumulator|.
  2. The each_with_object method ignores the return value of the block and only passes the initial accumulator object along to the next iteration. This is why we don?t need to use the merge method here.

Conclusion

Listening to the discussion in the video, and reading blog posts on the subject, it becomes apparent that using inject to convert an array to a hash was common practice before the each_with_object method existed.

The decision about which method you should use comes down to how well you know your Ruby toolbox. The inject method is really good at reducing a list to a value. The each_with_object method was created to solve problems like converting an array into a hash.

When converting an array to a hash I can?t come up with a single example of why I would want to use inject instead of each_with_object. The code is more readable, and I?m assuming more efficient (I can?t find any evidence to support this but if you know of any please let me know!) using each_with_object. If I ever need to convert an array into a hash, I know exactly what method I am going to use.

Thanks for Reading.

Resources

Full Code Reading Video

Better Hash Injection using each_with_object – CustomInk Technology Blog

A common Ruby pattern for injecting values from an Array into to a Hash is to use the Enumerable#inject method and pass?

technology.customink.com

Module: Enumerable (Ruby 2.2.3)

Module : Enumerable – Ruby 2.2.3

ruby-doc.org

Random code gist on the topic

19