From a759a251a4bf9022094db992c57dab1f827309c2 Mon Sep 17 00:00:00 2001 From: Dennis Ideler Date: Fri, 18 Mar 2016 00:13:48 +0000 Subject: [PATCH 1/3] Add benchmark for Hash#dig vs #[] vs #fetch --- README.md | 26 ++++++++++++++++++++++++++ code/hash/dig-vs-[]-vs-fetch.rb | 27 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 code/hash/dig-vs-[]-vs-fetch.rb diff --git a/README.md b/README.md index b1f393f..39b2db2 100644 --- a/README.md +++ b/README.md @@ -573,6 +573,32 @@ Comparison: Hash#fetch, string: 3981166.5 i/s - 1.89x slower ``` +##### `Hash#dig` vs `Hash#[]` vs `Hash#fetch` [code](code/hash/dig-vs-[]-fetch.rb) + +``` +$ ruby -v code/hash/dig-vs-\[\]-vs-fetch.rb +ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15] +Warming up -------------------------------------- + Hash#dig 144.192k i/100ms + Hash#[] 148.853k i/100ms + Hash#[] fallback 149.761k i/100ms + Hash#fetch 132.257k i/100ms + Hash#fetch fallback 120.420k i/100ms +Calculating ------------------------------------- + Hash#dig 6.253M (± 5.9%) i/s - 31.145M + Hash#[] 6.733M (± 5.9%) i/s - 33.641M + Hash#[] fallback 6.209M (± 5.7%) i/s - 31.001M + Hash#fetch 4.500M (± 5.0%) i/s - 22.484M + Hash#fetch fallback 3.330M (± 4.7%) i/s - 16.618M + +Comparison: + Hash#[]: 6732624.6 i/s + Hash#dig: 6252809.1 i/s - same-ish: difference falls within error + Hash#[] fallback: 6209365.5 i/s - same-ish: difference falls within error + Hash#fetch: 4499831.0 i/s - 1.50x slower + Hash#fetch fallback: 3330397.7 i/s - 2.02x slower +``` + ##### `Hash[]` vs `Hash#dup` [code](code/hash/bracket-vs-dup.rb) Source: http://tenderlovemaking.com/2015/02/11/weird-stuff-with-hashes.html diff --git a/code/hash/dig-vs-[]-vs-fetch.rb b/code/hash/dig-vs-[]-vs-fetch.rb new file mode 100644 index 0000000..c9929a9 --- /dev/null +++ b/code/hash/dig-vs-[]-vs-fetch.rb @@ -0,0 +1,27 @@ +require 'benchmark/ips' + +h = { a: { b: { c: { d: { e: "foo" } } } } } + +Benchmark.ips do |x| + x.report 'Hash#dig' do + h.dig(:a, :b, :c, :d, :e) + end + + x.report 'Hash#[]' do + h[:a][:b][:c][:d][:e] + end + + x.report 'Hash#[] fallback' do + ((((h[:a] || {})[:b] || {})[:c] || {})[:d] || {})[:e] + end + + x.report 'Hash#fetch' do + h.fetch(:a).fetch(:b).fetch(:c).fetch(:d).fetch(:e) + end + + x.report 'Hash#fetch fallback' do + h.fetch(:a, {}).fetch(:b, {}).fetch(:c, {}).fetch(:d, {}).fetch(:e, nil) + end + + x.compare! +end From 95b8ea491d5c4ab310c1166c2a280cd7f6356272 Mon Sep 17 00:00:00 2001 From: Dennis Ideler Date: Fri, 18 Mar 2016 17:55:02 +0000 Subject: [PATCH 2/3] Also benchmark the more common `Hash#[] &&` style --- README.md | 33 ++++++++++++++++++--------------- code/hash/dig-vs-[]-vs-fetch.rb | 6 +++++- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 39b2db2..65f361e 100644 --- a/README.md +++ b/README.md @@ -579,24 +579,27 @@ Comparison: $ ruby -v code/hash/dig-vs-\[\]-vs-fetch.rb ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15] Warming up -------------------------------------- - Hash#dig 144.192k i/100ms - Hash#[] 148.853k i/100ms - Hash#[] fallback 149.761k i/100ms - Hash#fetch 132.257k i/100ms - Hash#fetch fallback 120.420k i/100ms + Hash#dig 142.217k i/100ms + Hash#[] 153.313k i/100ms + Hash#[] || 145.380k i/100ms + Hash#[] && 121.401k i/100ms + Hash#fetch 137.236k i/100ms + Hash#fetch fallback 120.010k i/100ms Calculating ------------------------------------- - Hash#dig 6.253M (± 5.9%) i/s - 31.145M - Hash#[] 6.733M (± 5.9%) i/s - 33.641M - Hash#[] fallback 6.209M (± 5.7%) i/s - 31.001M - Hash#fetch 4.500M (± 5.0%) i/s - 22.484M - Hash#fetch fallback 3.330M (± 4.7%) i/s - 16.618M + Hash#dig 6.216M (± 6.2%) i/s - 31.003M + Hash#[] 6.676M (± 6.3%) i/s - 33.269M + Hash#[] || 6.160M (± 6.2%) i/s - 30.675M + Hash#[] && 3.096M (± 5.4%) i/s - 15.539M + Hash#fetch 4.425M (± 5.5%) i/s - 22.095M + Hash#fetch fallback 3.279M (± 5.3%) i/s - 16.441M Comparison: - Hash#[]: 6732624.6 i/s - Hash#dig: 6252809.1 i/s - same-ish: difference falls within error - Hash#[] fallback: 6209365.5 i/s - same-ish: difference falls within error - Hash#fetch: 4499831.0 i/s - 1.50x slower - Hash#fetch fallback: 3330397.7 i/s - 2.02x slower + 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 ``` ##### `Hash[]` vs `Hash#dup` [code](code/hash/bracket-vs-dup.rb) diff --git a/code/hash/dig-vs-[]-vs-fetch.rb b/code/hash/dig-vs-[]-vs-fetch.rb index c9929a9..87a7fa4 100644 --- a/code/hash/dig-vs-[]-vs-fetch.rb +++ b/code/hash/dig-vs-[]-vs-fetch.rb @@ -11,10 +11,14 @@ h[:a][:b][:c][:d][:e] end - x.report 'Hash#[] fallback' do + x.report 'Hash#[] ||' do ((((h[:a] || {})[:b] || {})[:c] || {})[:d] || {})[:e] end + x.report 'Hash#[] &&' do + h[:a] && h[:a][:b] && h[:a][:b][:c] && h[:a][:b][:c][:d] && h[:a][:b][:c][:d][:e] + end + x.report 'Hash#fetch' do h.fetch(:a).fetch(:b).fetch(:c).fetch(:d).fetch(:e) end From 437d8f86e671bb0357d63fd5dae6dd25ab3f1bf2 Mon Sep 17 00:00:00 2001 From: Dennis Ideler Date: Sun, 20 Mar 2016 11:40:54 +0000 Subject: [PATCH 3/3] :memo: Introduce Hash#dig and link to more info --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 65f361e..e8404a6 100644 --- a/README.md +++ b/README.md @@ -575,6 +575,10 @@ Comparison: ##### `Hash#dig` vs `Hash#[]` vs `Hash#fetch` [code](code/hash/dig-vs-[]-fetch.rb) +[Ruby 2.3 introduced `Hash#dig`](http://ruby-doc.org/core-2.3.0/Hash.html#method-i-dig) which is a readable +and performant option for retrieval from a nested hash, returning `nil` if an extraction step fails. +See [#102 (comment)](https://github.com/JuanitoFatas/fast-ruby/pull/102#issuecomment-198827506) for more info. + ``` $ ruby -v code/hash/dig-vs-\[\]-vs-fetch.rb ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]