fastruby / fast-ruby

:dash: Writing Fast Ruby :heart_eyes: -- Collect Common Ruby idioms.
https://github.com/fastruby/fast-ruby
5.67k stars 376 forks source link

Add benchmark for Hash#dig vs #[] vs #fetch #102

Closed dideler closed 8 years ago

dideler commented 8 years ago

Comparison of how Ruby 2.3.0's Hash#dig performs to similar methods.

Unsafe retrieval options are included. I can remove them if you consider them noisy.

ixti commented 8 years ago

More interesting would be to compare dig vs alternatives upon "broken" path:

H = { :a => { :b => { :d => true } } }

H.dig(:a, :b, :c, :d) # => nil
H[:a] && H[:a][:b] && H[:a][:b][:c] && H[:a][:b][:c][:d] # => nil
dideler commented 8 years ago

More interesting would be to compare dig vs alternatives upon "broken" path:

I find the safe path most interesting because you can compare more options, but here are all cases.

Safe: h = { a: { b: { c: { d: { e: "foo" } } } } }

Comparison:
             Hash#[]:  6676415.9 i/s
            Hash#dig:  6215966.7 i/s - same-ish: difference falls within error
          Hash#[] ||:  6160177.6 i/s - same-ish: difference falls within error
          Hash#fetch:  4424551.0 i/s - 1.51x slower
 Hash#fetch fallback:  3278599.3 i/s - 2.04x slower
          Hash#[] &&:  3096090.4 i/s - 2.16x slower

Broken at last key: h = { a: { b: { c: { d: { x: "foo" } } } } } The Hash#fetch benchmark is excluded because it doesn't gracefully fail.

Comparison:
             Hash#[]:  6391117.6 i/s
          Hash#[] ||:  5775857.7 i/s - same-ish: difference falls within error
            Hash#dig:  5599916.6 i/s - same-ish: difference falls within error
 Hash#fetch fallback:  3278820.7 i/s - 1.95x slower
          Hash#[] &&:  2920215.9 i/s - 2.19x slower

Broken at intermediate key: h = { a: { b: { c: { x: { e: "foo" } } } } } The Hash#fetch and Hash#[] benchmarks are excluded because they do not gracefully fail.

Comparison:
            Hash#dig:  5525802.5 i/s
          Hash#[] ||:  4866123.4 i/s - same-ish: difference falls within error
          Hash#[] &&:  3727126.8 i/s - 1.48x slower
 Hash#fetch fallback:  2921706.4 i/s - 1.89x slower

Hash#dig does well in all cases. It reads better than the other options and is consistently performant.

ixti commented 8 years ago

@dideler I'm absolutely agree that dig is a winner :D and I guess the only my proposal is to add link to https://github.com/JuanitoFatas/fast-ruby/pull/102#issuecomment-198827506 in readme :D

dideler commented 8 years ago

:+1:, how's 437d8f86e671bb0357d63fd5dae6dd25ab3f1bf2?

ixti commented 8 years ago

LGTM! :+1:

JuanitoFatas commented 8 years ago

Thanks everyone 👏 ! Merged as d6e1ac0.

@dideler Dennis would you like to be a collaborator to this repository 😊 ?

dideler commented 8 years ago

Thanks @JuanitoFatas - I would love to be a collaborator!

JuanitoFatas commented 8 years ago

Thanks @JuanitoFatas - I would love to be a collaborator!

Yay! ❤️