Back to blog overview

May 18, 2020

Enumerable#index _by For Better Hash Building In Rails

Use Enumerable#index_by over Enumerable#each_with_object

Chris White

&

Senior Software Engineer
Fort Collins, CO


Ruby hashes are awesome! They allow us to efficiently access data by a key. A common task in data processing is to build hashes using Enumerable#each_with_object so we can quickly access related data during processing steps

In this example, we need to process a large amount of photo data by invoking process_photo, which needs a photo from our data and an instance from our Photographer model

-- CODE language-ruby line-numbers --# Bad, we will perform photo_data.count database requests
photo_data.each do |photo|
 process_photo(photo, Photographer.find_by(key: photo.key))
end

-- CODE language-ruby line-numbers --# Better, we perform a single database request
all_keys = photo_data.map(&:key).uniq
photographers_by_key = Photographer
                      .where(key: all_keys)
                      .each_with_index({}) do |photographer, accumulator|
 accumulator[photographer.key] = photographer
end
photo_data.each do |photo|
 process_photo(photo, photographers_by_key[photo.key])
end

Thanks to a recent addition to rubocop-rails, I learned that we can use Rails’ ActiveSupport method Enumerable#index_by to make this manipulation even easier

-- CODE language-ruby line-numbers --# Even Better, Enumerable#index_by simplifies the construction of our hash
all_keys = photo_data.map(&:key).uniq
photographers_by_key = Photographer.where(key: all_keys).index_by(&:key)
photo_data.each do |photo|
 process_photo(photo, photographers_by_key[photo.key])
end

TLDR: use Enumerable#index_by over Enumerable#each_with_object

-- CODE language-ruby line-numbers --# Good
photographers_by_key = Photographer
                      .where(key: all_keys)
                      .each_with_index({}) do |photographer, accumulator|
accumulator[photographer.key] = photographer
end

-- CODE language-ruby line-numbers --# Better
photographers_by_key = Photographer.where(key: all_keys).index_by(&:key)

Let's Chat

Are you ready to build something brilliant? We're ready to help.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Learn Redwood

Are you ready to future-proof your career? Stay in the loop of our Learn with Redwood Masterclass.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.