I was doing some playing with some implementations for Hash#== and ended
up with some very counterintuitive timings.

I have four equals methods, and I would have expected their performance
to run (from best to worst):

directInject - stops evaluating == after first bad match, no
intermediate arrays 
keysInject - as above, but must create keys array
directCollect - evaluated == for all items all the time, intermediate
array of results
keysCollect - as above, but must create keys array.

Actually running the code however, I ended up with the following
timings:

keysCollect
equal     0.18
not equal 0.11

directCollect
equal     0.221
not equal 0.24

directInject
equal     0.31
not equal 0.221

keysInject
equal     0.24
not equal 0.15

Can anybody shed any light on why it's not performing as I would assume?


-----

def keysCollect(hash1, hash2)
  hash1.size == hash2.size && 
    !(hash1.keys.collect{|k| !hash2[k].nil? && hash1[k] == hash2[k]
}.include?(false))
end
def directCollect(hash1, hash2)
  hash1.size == hash2.size && 
    !(hash1.collect{|k,v| hash2[k] == v }.include?(false))
end
def directInject(hash1, hash2)
  hash1.size == hash2.size && 
    hash1.inject(true) { |val, kv| val && hash2[kv[0]] == kv[1] }
end
def keysInject(hash1, hash2)
  hash1.size == hash2.size && 
    hash1.keys.inject(true) { |val, k| val && hash1[k] == hash2[k] }
end

def time(p, *args)
  time = Time.now
  1000.times { p.call *args}
  Time.now - time
end

hash1 = Hash.new
hash2 = Hash.new
xx = 'a'
50.times { hash1[xx] = xx; xx = xx.next }
50.times { hash2[xx] = xx; xx = xx.next }

[:keysCollect, :directCollect, :directInject, :keysInject].each { |s|
  puts s
  puts "equal     #{time(method(s), hash1, hash1)}"
  puts "not equal #{time(method(s), hash1, hash2)}"
}
#####################################################################################
This email has been scanned by MailMarshal, an email content filter.
#####################################################################################