Skip to content

Instantly share code, notes, and snippets.

@danielfone
Created October 27, 2014 03:10
Show Gist options
  • Select an option

  • Save danielfone/3607bad04789d43b2676 to your computer and use it in GitHub Desktop.

Select an option

Save danielfone/3607bad04789d43b2676 to your computer and use it in GitHub Desktop.
require_relative 'micro_bench'
# Various methods to update every value in a hash in place
module HashUpdate
module_function
# also Hash#update
def merge!(hash)
hash.merge!(hash) do |key, value|
value + 1
end
end
def inject_existing(hash)
hash.inject(hash) do |hash, (key, value)|
hash[key] = value + 1; hash
end
end
def each(hash)
hash.each do |key, value|
hash[key] = value + 1
end
end
def each_with_object(hash)
hash.each_with_object(hash) do |(key, value), old_hash|
old_hash[key] = value + 1
end
end
end
# Various methods to map values from one hash to another with identical keys
module HashMap
module_function
def dup_merge(hash)
hash.dup.merge!(hash) do |key, value|
value + 1
end
end
def merge(hash)
hash.merge(hash) do |key, value|
value + 1
end
end
def inject_new(hash)
hash.inject({}) do |new_hash, (key, value)|
new_hash[key] = value + 1; new_hash
end
end
def each(hash)
new_hash = {}
hash.each do |key, value|
new_hash[key] = value + 1
end
new_hash
end
def tap(hash)
{}.tap do |new_hash|
hash.each do |key, value|
new_hash[key] = value + 1
end
end
end
def each_with_object(hash)
hash.each_with_object({}) do |(key, value), new_hash|
new_hash[key] = value + 1
end
end
def hash_map(hash)
Hash[hash.map { |k,v| [k,v+1] }]
end
# For the lols
# http://stackoverflow.com/a/13662576/1848
def map_reduce(hash)
hash.map { |k,v| {k => v+1} }.reduce :merge
end
end
VALUES = Hash[*(1..1000).to_a]
TEST = {
a: 1,
b: 2,
c: 3,
}
RESULT = {
a: 2,
b: 3,
c: 4,
}
b = MicroBench.new HashUpdate, VALUES, TEST => RESULT
b.check *[
:merge!,
:inject_existing,
:each,
:each_with_object,
]
b = MicroBench.new HashMap, VALUES, TEST => RESULT
b.check *[
:merge,
:dup_merge,
:inject_new,
:each,
:hash_map,
# :map_reduce,
:each_with_object,
:tap,
]
=begin
$ ruby ./update_hash_bench.rb
Testing [:merge!, :inject_existing, :each, :each_with_object]...
all good.
Calculating -------------------------------------
merge! 1582 i/100ms
inject_existing 941 i/100ms
each 1468 i/100ms
each_with_object 959 i/100ms
-------------------------------------------------
merge! 16327.9 (±3.1%) i/s - 9492 in 0.581935s
inject_existing 9735.6 (±0.9%) i/s - 5646 in 0.579978s
each 15143.6 (±1.2%) i/s - 8808 in 0.581722s
each_with_object 9682.1 (±1.0%) i/s - 5754 in 0.594349s
Comparison:
merge!: 16327.9 i/s
each: 15143.6 i/s - 1.08x slower
inject_existing: 9735.6 i/s - 1.68x slower
each_with_object: 9682.1 i/s - 1.69x slower
Testing [:merge, :inject_new, :each, :hash_map, :each_with_object, :tap]...
all good.
Calculating -------------------------------------
merge 399 i/100ms
inject_new 431 i/100ms
each 471 i/100ms
hash_map 385 i/100ms
each_with_object 418 i/100ms
tap 509 i/100ms
-------------------------------------------------
merge 3985.4 (±22.6%) i/s - 1995 in 0.542334s
inject_new 4194.7 (±4.1%) i/s - 2155 in 0.514623s
each 5835.0 (±33.1%) i/s - 3297 in 0.648399s
hash_map 3863.7 (±6.5%) i/s - 1925 in 0.500590s
each_with_object 4346.3 (±1.0%) i/s - 2508 in 0.577100s
tap 5516.0 (±31.5%) i/s - 3054 in 0.620976s
Comparison:
each: 5835.0 i/s
tap: 5516.0 i/s - 1.06x slower
each_with_object: 4346.3 i/s - 1.34x slower
inject_new: 4194.7 i/s - 1.39x slower
merge: 3985.4 i/s - 1.46x slower
hash_map: 3863.7 i/s - 1.51x slower
=end
@danielfone
Copy link
Author

The wider distribution on the HashMap benchmarks is due to the object creation triggering GC, disabling will bring that variance down to <10%.

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