image by Sabri Tuzcu

Benchmarking each_with_object Against inject when building Hashes from Arrays

I read Better Hash Injection using each_with_object with interest.

RailsConf 2024

I'm co-chairing RailsConf 2024 in Detroit May 7–9. Come and join us 

I’d long known that using Ruby’s Hash#merge! rather than Hash#merge was much faster: merge hash in place in memory, don’t copy and assign. I’d never come across each_with_index in the wild, at least and remembered.

What a fool I’ve been.

Rather than use code like either of these…

array_of_stuff.inject({}) do |result, element|
  result[] = element.value

array_of_stuff.inject({}) do |result, element|
  result.merge!( => element.value)

…it’s much more idiomatic Ruby to use each_with_object.

array_of_stuff.each_with_object({}) do |element, result|
  result[] = element.value

I was interested to see how this idiomatic Ruby performed. I put together a little script to test the various ways of generating a Hash from an decent-sized array of simple Struct-based objects. I used the benchmark-ips gem.

require 'benchmark/ips'

User =, :stuff)
a = { |i|, stuff: rand(1000)) }

Benchmark.ips do |x|'assign&return') do
    a.inject({}) { |memo, i| memo[] = i.stuff; memo }
  end'merge') do
    a.inject({}) { |memo, i| memo.merge( => i.stuff) }
  end'merge!') do
    a.inject({}) { |memo, i| memo.merge!( => i.stuff) }
  end'map with tuples') do { |i| [, i.stuff] }.to_h
  end'each_with_object') do
    a.each_with_object({}) { |i, memo| memo[] = i.stuff }

The results were interesting.

assign&return 3136.7(±8.2%) i/s
merge 5.9(±0.0%) i/s
merge! 1168.0(±28.3%) i/s
map with tuples 2400.8(±23.0%) i/s
each_with_object 3220.8(±3.3%) i/s

Turns out the most idiomatic code is also the fastest. Followed surprisingly closely by the ‘do the simplest thing’ variant, but not by a huge amount.

PS If you’re using merge without the ! inside loops like this… just don’t.

Brighton Ruby 2024

Still running UK’s friendliest, Ruby event on Friday 28th June. Ice cream + Ruby 

Last updated on October 21st, 2014 by @andycroll

An email newsletter, with one Ruby/Rails technique delivered with a ‘why?’ and a ‘how?’ every two weeks. It’s deliberately brief, focussed & opinionated.