Skip to content

Instantly share code, notes, and snippets.

@juniorz
Last active August 29, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save juniorz/2556b41a35e3db9d2557 to your computer and use it in GitHub Desktop.
Save juniorz/2556b41a35e3db9d2557 to your computer and use it in GitHub Desktop.
Stringify hash keys
% ruby -v
ruby 1.8.6 (2010-09-02 patchlevel 420) [i686-darwin13.1.0]
% ruby ./stringify_keys.rb
Rehearsal ------------------------------------------------
slow random: 1.750000 0.000000 1.750000 ( 1.763713)
slow worst: 2.730000 0.040000 2.770000 ( 2.768919)
fast random: 1.350000 0.000000 1.350000 ( 1.355698)
fast worst: 2.520000 0.010000 2.530000 ( 2.525618)
--------------------------------------- total: 8.400000sec
user system total real
slow random: 1.740000 0.020000 1.760000 ( 1.764548)
slow worst: 2.690000 0.030000 2.720000 ( 2.726322)
fast random: 1.320000 0.000000 1.320000 ( 1.318631)
fast worst: 2.390000 0.010000 2.400000 ( 2.400333)
/tmp/foo %
% jruby -v
jruby 1.3.1 (ruby 1.8.6p287) (2009-06-15 2fd6c3d) (Java HotSpot(TM) 64-Bit Server VM 1.8.0) [x86_64-java]
% jruby ./stringify_keys.rb
Rehearsal ------------------------------------------------
slow random: 0.835000 0.000000 0.835000 ( 0.682000)
slow worst: 0.440000 0.000000 0.440000 ( 0.440000)
fast random: 0.927000 0.000000 0.927000 ( 0.927000)
fast worst: 2.836000 0.000000 2.836000 ( 2.836000)
--------------------------------------- total: 5.038000sec
user system total real
slow random: 0.377000 0.000000 0.377000 ( 0.377000)
slow worst: 0.464000 0.000000 0.464000 ( 0.464000)
fast random: 0.674000 0.000000 0.674000 ( 0.674000)
fast worst: 1.332000 0.000000 1.332000 ( 1.332000)
% ruby -v
ruby 1.8.7 (2013-06-27 patchlevel 374) [i686-darwin13.0.0]
% ruby ./stringify_keys.rb
Rehearsal ------------------------------------------------
slow random: 2.110000 0.000000 2.110000 ( 2.117278)
slow worst: 2.620000 0.040000 2.660000 ( 2.656150)
fast random: 1.480000 0.000000 1.480000 ( 1.490607)
fast worst: 2.060000 0.010000 2.070000 ( 2.069680)
--------------------------------------- total: 8.320000sec
user system total real
slow random: 1.900000 0.020000 1.920000 ( 1.921963)
slow worst: 2.500000 0.030000 2.530000 ( 2.538800)
fast random: 1.450000 0.000000 1.450000 ( 1.467388)
fast worst: 2.210000 0.010000 2.220000 ( 2.221262)
% ruby -v
ruby 1.9.3p545 (2014-02-24 revision 45159) [x86_64-darwin13.1.0]
% ruby ./stringify_keys.rb
Rehearsal ------------------------------------------------
slow random: 1.700000 0.020000 1.720000 ( 1.735894)
slow worst: 2.080000 0.020000 2.100000 ( 2.097329)
fast random: 0.830000 0.010000 0.840000 ( 0.834736)
fast worst: 1.260000 0.000000 1.260000 ( 1.262355)
--------------------------------------- total: 5.920000sec
user system total real
slow random: 1.710000 0.020000 1.730000 ( 1.741885)
slow worst: 2.130000 0.030000 2.160000 ( 2.164398)
fast random: 0.780000 0.000000 0.780000 ( 0.786673)
fast worst: 1.510000 0.000000 1.510000 ( 1.519155)
% ruby -v
jruby 1.7.12 (1.9.3p392) 2014-04-15 643e292 on Java HotSpot(TM) 64-Bit Server VM 1.8.0-b132 +indy [darwin-x86_64]
% ruby ./stringify_keys.rb
Rehearsal ------------------------------------------------
slow random: 2.370000 0.040000 2.410000 ( 1.085000)
slow worst: 0.600000 0.020000 0.620000 ( 0.537000)
fast random: 1.650000 0.020000 1.670000 ( 0.680000)
fast worst: 0.570000 0.010000 0.580000 ( 0.526000)
--------------------------------------- total: 5.280000sec
user system total real
slow random: 0.380000 0.010000 0.390000 ( 0.370000)
slow worst: 0.590000 0.010000 0.600000 ( 0.514000)
fast random: 0.360000 0.000000 0.360000 ( 0.363000)
fast worst: 0.470000 0.010000 0.480000 ( 0.464000)
require 'benchmark'
# NOT thread-safe
def stringify(options)
# 1.8.6 (eventually) says: each': hash modified during iteration (RuntimeError)
# 1.8.7 says: `each': hash modified during iteration (RuntimeError)
# 1.9 says: `merge!': can't add a new key into hash during iteration (RuntimeError)
# jruby-1.7.3 says: RuntimeError: can't add a new key into hash during iteration
# merge! at org/jruby/RubyHash.java:1661
options.each { |key, val| options.merge!(key.to_s => val) }
options
end
# fixing thread-safety issue (only)
def stringify_slow(options)
opts = options.dup
opts.each { |key, val| options.merge!(key.to_s => val) }
options
end
def stringify_fast(options)
non_string_pairs = options.reject{|key, val| key.is_a?(String)}
stringified_values = non_string_pairs.map{|key, val| [key.to_s, val]}
if RUBY_VERSION < "1.8.7"
stringified_values.flatten!
options.merge!(Hash[*stringified_values])
else
options.merge!(Hash[stringified_values])
end
options
end
random_hash = {}
worst_case = {}
500.times do |i|
key = i.to_s
random_hash[rand() > 0.5 ? key.to_sym : key] = i
worst_case[key.to_sym] = i
end
n = 1_000
Benchmark.bmbm(7) do |x|
x.report("slow random:") { for i in 1..n; stringify_slow(random_hash); end }
x.report("slow worst:") { for i in 1..n; stringify_slow(worst_case); end }
x.report("fast random:") { for i in 1..n; stringify_fast(random_hash); end }
x.report("fast worst:") { for i in 1..n; stringify_fast(worst_case); end }
end
@juniorz
Copy link
Author

juniorz commented May 3, 2014

The second implementation is thread-safe and looks (slightly) faster on every implementation but JRuby 1.3.1 (I put the blame on the flatten! plus splat - added only for the sake of compatibility).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment