Skip to content

Instantly share code, notes, and snippets.

@spraints
Forked from mediocretes/gist:1793402
Created February 11, 2012 02:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save spraints/1795543 to your computer and use it in GitHub Desktop.
Save spraints/1795543 to your computer and use it in GitHub Desktop.
class Hash
def self.nmerge(*hashes, &block)
keys = hashes.map(&:keys).flatten.uniq
rhashes = hashes.reverse
keys.inject({ }) do |output, key|
if block
output[key] = block.call(key, hashes.map{ |x| x[key]})
else
rhashes.each do |hash|
if hash[key]
output[key] = hash[key]
break
end
end
end
output
end
end
def self.mmerge(*hashes)
hashes.inject { |a,b| a.merge b }
end
def self.lmerge(*hashes)
hashes.inject({}) { |a,b| a.merge! b }
end
end
require 'benchmark'
one = {:one => 1, :two => 1}
two = {:two => 2, :three => 2}
three = {:three => 3, :four => 3}
puts Hash.nmerge(one, two, three).inspect
puts Hash.mmerge(one, two, three).inspect
puts Hash.lmerge(one, two, three).inspect
Benchmark.bmbm do |x|
x.report('nmerge') { 100000.times { Hash.nmerge one, two, three } }
x.report('mmerge') { 100000.times { Hash.mmerge one, two, three } }
x.report('lmerge') { 100000.times { Hash.lmerge one, two, three } }
end
>> ruby nm.rb
{:one=>1, :two=>2, :three=>3, :four=>3}
{:one=>1, :two=>2, :three=>3, :four=>3}
{:one=>1, :two=>2, :three=>3, :four=>3}
Rehearsal ------------------------------------------
nmerge 1.220000 0.010000 1.230000 ( 1.254603)
mmerge 0.460000 0.000000 0.460000 ( 0.469838)
lmerge 0.260000 0.000000 0.260000 ( 0.259385)
--------------------------------- total: 1.950000sec
user system total real
nmerge 1.070000 0.000000 1.070000 ( 1.068250)
mmerge 0.440000 0.000000 0.440000 ( 0.443846)
lmerge 0.270000 0.010000 0.280000 ( 0.274417)
>> ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin10.8.0]
@mediocretes
Copy link

class Hash
  def self.nmerge(*hashes, &block)
    keys = hashes.map(&:keys).flatten.uniq
    rhashes = hashes.reverse
    keys.inject({ }) do |output, key|
      if block
        output[key] = block.call(key, hashes.map{ |x| x[key]})
      else
        rhashes.each do |hash|
          if hash[key]
            output[key] = hash[key]
            break
          end
        end
      end
      output
    end
  end
  def self.mmerge(*hashes, &block)
    hashes.inject { |a,b| a.merge(b, &block) }
  end
  def self.lmerge(*hashes, &block)
    hashes.inject({}) { |a,b| a.merge! b, &block }
  end
end

require 'benchmark'

one = (1..100).inject({ }) { |result, element| result[element.to_s] = element; result}
two = (26..125).inject({ }) { |result, element| result[element.to_s] = element; result}
three = (51..150).inject({ }) { |result, element| result[element.to_s] = element; result}
four = (76..175).inject({ }) { |result, element| result[element.to_s] = element; result}

block1 = lambda { |key, values| values.inject(0){ |sum, val| sum + val.to_i} }
block2 = lambda { |key, left, right| left+ right }

hashes = [one, two, three, four, one.dup, two.dup, three.dup, four.dup]
puts Hash.nmerge(*hashes, &block1).inspect
puts Hash.mmerge(*hashes, &block2).inspect
puts Hash.lmerge(*hashes, &block2).inspect


Benchmark.bmbm do |x|
  x.report('nmerge') { 10000.times { Hash.nmerge(*hashes, &block1)} }
  x.report('mmerge') { 10000.times { Hash.mmerge(*hashes, &block2)} }
  x.report('lmerge') { 10000.times { Hash.lmerge(*hashes, &block2)} }
end
         user     system      total        real

nmerge 9.290000 0.020000 9.310000 ( 9.294319)
mmerge 5.330000 0.120000 5.450000 ( 5.450449)
lmerge 2.300000 0.020000 2.320000 ( 2.318999)

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