(Pr)#each_with_object

Anna Rasshivkina
Feb 27, 2016 · 4 min read

Part of my series of easy primers on methods to eliminate code smell: needlessly lengthy or complex code.

each_with_object

Code smell: You’re creating an empty hash or array. Then you’re iterating over another hash or array to retrieve information to put into your empty object. Then you’re returning your newly created object.

#Each_with_object was my first favorite Ruby method. I came across it many times before I started at the Flatiron School, but it wasn’t until my first week that each_with_object, which had always seemed indecipherably complex to me, clicked neatly into place. And then it was like a magic wand capable of transforming clunky, beastly methods into things of beauty. This higher-level iterator enables you to turn 3 steps into 1, and it’s useful in a wide variety of circumstances. Let’s start with a very simple and illustrative example from Ruby’s own documentation. In this method, we want to take a series of numbers, multiply each one by 2, and put it into a new array:

  i  = each number in our range (1-10)  a  = a variable we create to represent our empty array  a << i * 2  = put ( shovel ) every number * 2 into our new array
  i  = each number in our range (1-10)  a  = a variable we create to represent our empty array  a << i * 2  = put ( shovel ) every number * 2 into our new array

In the example above, we start with a range of numbers, 1–10, which is essentially like an array. We want to create a new array object by multiplying each number by 2. Our new object, an empty array, goes in the parentheses ([]). Our first variable i stands for each integer in our range, and our second variable a stands for our object, the new array. Then we iterate over each integer, multiplying it by 2 and putting it into the array. The method automatically returns our new array.

It’s common that we have a set of information (like an array or hash), and we need to go through it, extract some info, and use that info somewhere else. Let’s look at one other, more realistic example.

Say you have an array of names [“Gob”, “Lucille”, “George Michael”]. You want to be able to add information about each of these people, so you need to create a new hash, where each name is a key that points to additional information {“Gob” => {}, “Lucille” => {}, “George Michael” => {}}.

Without #each_with_object, you’d have to create your new hash, iterate over your array and create a hash key from each name, then return the new hash:

 1) create our empty hash 2) go over each element in our array and use it to fill our new hash 3) .each returns our original array 4) return our new hash
 1) create our empty hash 2) go over each element in our array and use it to fill our new hash 3) .each returns our original array 4) return our new hash

Now let’s see this method using #each_with_object:

 1) we create our new hash in the parentheses 2)   our 1st variable represents each  name  in our names array. our 2nd variable represents our new  hash of people  3) .each_with_object automatically returns our new object
 1) we create our new hash in the parentheses 2)   our 1st variable represents each  name  in our names array. our 2nd variable represents our new  hash of people  3) .each_with_object automatically returns our new object

Now we’re able to accomplish the same thing using just one step instead of three!

You can save the result of your #each_with_object method to a variable to use it again later:

people = names.each_with_object({}) { |name, people_hash| people_hash[name] = {} }

(If your block of code contains only one line (like people_hash[name] = {}), you can use curly braces instead of do/end and put everything on a single line for prettier code.)

You can also use #each_with_object to iterate over a hash. For example, let’s say that we have our people hash, and it’s now filled out with some information, like hobbies:

Image for post
Image for post

We want to get everybody’s hobbies and put them into their own array. We can accomplish it easily by using #each_with_object on our hash:

 1) we create our empty array in the parentheses 2)  (name, info)  represents the keys and values of our hash. We put these in parentheses, followed by a variable for our new object—in this case, our  array of hobbies  3) remember, info is another hash: {
 1) we create our empty array in the parentheses 2)  (name, info)  represents the keys and values of our hash. We put these in parentheses, followed by a variable for our new object—in this case, our  array of hobbies  3) remember, info is another hash: {

Once you get comfortable, you can start start condensing your short methods into single lines of code and using method chaining to make them even more succinct. For example:

people_hash.each_with_object([]) { |(name,info),hobby_array| hobby_array << info["hobbies"] }.flatten

So, to review, we went from this:

Image for post
Image for post

To this:

Image for post
Image for post

This is probably not remotely exciting to you unless you’re a fellow coding geek — but hey, one has to appreciate the little things in life. (Get it??)

Anyway, the takeaway:

When you’re using .each to fill a new object, use each_with_object.

Synaptic Sugar

Code blog covering Ruby, Javascript, HTML, CSS, and other…

Anna Rasshivkina

Written by

All things language. Writer, translator, coder. www.thesewords.live

Synaptic Sugar

Code blog covering Ruby, Javascript, HTML, CSS, and other assorted coding topics. Attempting to make simple the confusing, with minimum nerd jargon. Written by Anna Rasshivkina.

Anna Rasshivkina

Written by

All things language. Writer, translator, coder. www.thesewords.live

Synaptic Sugar

Code blog covering Ruby, Javascript, HTML, CSS, and other assorted coding topics. Attempting to make simple the confusing, with minimum nerd jargon. Written by Anna Rasshivkina.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store