From: Ryan Davis Date: 2011-01-20T08:13:33+09:00 Subject: Re: Improving performance of hash math On Jan 18, 2011, at 21:23 , dblock wrote: >> Switch to using #each with an explicit accumulator variable instead of #inject. > > Looks about twice as slow. Either way, about 36% of the time is spent > in Hash.each. I don't agree with Gary's suggestion, because in this case it is a proper application of inject, but if you think it is 2x slower, then you're benchmarking is probably at fault. My measurements show each to be roughly equivalent on 1.9 and quite a bit faster on 1.8. That could be explained by my modification to your treatment of rhs or it could also be explained by my fake data. % ./q.rb 10000 # of iterations = 10000 user system total real null_time 0.000000 0.000000 0.000000 ( 0.001118) euclidian_distance1 18.960000 0.010000 18.970000 ( 19.011762) euclidian_distance2 13.050000 0.010000 13.060000 ( 13.069581) euclidian_distance3 13.090000 0.010000 13.100000 ( 13.109778) against: def euclidian_distance1(lhs, rhs) @s = lhs.inject(0.0) do |s, (k,v)| rhs.has_key?(k) ? (s + (v - rhs[k])**2) : (s + v**2) end @s = rhs.inject(@s) do |s, (k,v)| lhs.has_key?(k) ? s : (s + v**2) end @s end def euclidian_distance2(lhs, rhs) s = 0.0 lhs.each do |k,v| s += rhs.has_key?(k) ? ((v - rhs[k])**2) : (v**2) end rhs.each do |k,v| s += v**2 if lhs.has_key?(k) end s end def euclidian_distance3(lhs, rhs) s = lhs.inject(0.0) do |n, (k,v)| n + (rhs.has_key?(k) ? v - rhs[k] : v)**2 end rhs.each do |k,v| s += v**2 if lhs.has_key? k end s end