Created
July 12, 2009 11:22
-
-
Save methodmissing/145604 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'benchmark' | |
class Hash | |
def diff(h2) | |
dup.delete_if { |k, v| h2[k] == v }.merge(h2.dup.delete_if { |k, v| has_key?(k) }) | |
end | |
def faster_diff(h2) | |
dup.delete_if { |k, v| h2[k] == v }.merge!(h2.dup.delete_if { |k, v| has_key?(k) }) | |
end | |
def deep_merge(other_hash) | |
merge(other_hash) do |key, oldval, newval| | |
oldval = oldval.to_hash if oldval.respond_to?(:to_hash) | |
newval = newval.to_hash if newval.respond_to?(:to_hash) | |
oldval.class.to_s == 'Hash' && newval.class.to_s == 'Hash' ? oldval.deep_merge(newval) : newval | |
end | |
end | |
def faster_deep_merge(other_hash) | |
merge(other_hash) do |key, oldval, newval| | |
oldval = oldval.to_hash if oldval.respond_to?(:to_hash) | |
newval = newval.to_hash if newval.respond_to?(:to_hash) | |
oldval.is_a?( Hash ) && newval.is_a?( Hash ) ? oldval.deep_merge(newval) : newval | |
end | |
end | |
def reverse_merge(other_hash) | |
other_hash.merge(self) | |
end | |
def reverse_merge!(other_hash) | |
replace(reverse_merge(other_hash)) | |
end | |
def with_indifferent_access | |
hash = ActiveSupport::HashWithIndifferentAccess.new(self) | |
hash.default = self.default | |
hash | |
end | |
def with_faster_indifferent_access | |
hash = ActiveSupport::FasterHashWithIndifferentAccess.new(self) | |
hash.default = self.default | |
hash | |
end | |
def reverse_merge!(other_hash) | |
replace(reverse_merge(other_hash)) | |
end | |
def faster_reverse_merge!(other_hash) | |
merge!( other_hash ){|k,o,n| o } | |
end | |
end | |
module ActiveSupport | |
class HashWithIndifferentAccess < Hash | |
def initialize(constructor = {}) | |
if constructor.is_a?(Hash) | |
super() | |
update(constructor) | |
else | |
super(constructor) | |
end | |
end | |
def default(key = nil) | |
if key.is_a?(Symbol) && include?(key = key.to_s) | |
self[key] | |
else | |
super | |
end | |
end | |
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer) | |
alias_method :regular_update, :update unless method_defined?(:regular_update) | |
def []=(key, value) | |
regular_writer(convert_key(key), convert_value(value)) | |
end | |
def update(other_hash) | |
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) } | |
self | |
end | |
alias_method :merge!, :update | |
def key?(key) | |
super(convert_key(key)) | |
end | |
alias_method :include?, :key? | |
alias_method :has_key?, :key? | |
alias_method :member?, :key? | |
def fetch(key, *extras) | |
super(convert_key(key), *extras) | |
end | |
def values_at(*indices) | |
indices.collect {|key| self[convert_key(key)]} | |
end | |
def dup | |
HashWithIndifferentAccess.new(self) | |
end | |
def merge(hash) | |
self.dup.update(hash) | |
end | |
def reverse_merge(other_hash) | |
super other_hash.with_indifferent_access | |
end | |
def reverse_merge!(other_hash) | |
replace(reverse_merge( other_hash )) | |
end | |
def delete(key) | |
super(convert_key(key)) | |
end | |
def stringify_keys!; self end | |
def symbolize_keys!; self end | |
def to_options!; self end | |
def to_hash | |
Hash.new(default).merge(self) | |
end | |
protected | |
def convert_key(key) | |
key.kind_of?(Symbol) ? key.to_s : key | |
end | |
def convert_value(value) | |
case value | |
when Hash | |
value.with_indifferent_access | |
when Array | |
value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e } | |
else | |
value | |
end | |
end | |
end | |
end | |
module ActiveSupport | |
class FasterHashWithIndifferentAccess < HashWithIndifferentAccess | |
def to_hash | |
Hash.new(default).merge!(self) | |
end | |
end | |
end | |
HashWithIndifferentAccess = ActiveSupport::HashWithIndifferentAccess | |
FasterHashWithIndifferentAccess = ActiveSupport::FasterHashWithIndifferentAccess | |
first = { :one => 1, :two => 2, :three => 3 } | |
second = { :four => 4, :five => 5, :six => 6 } | |
first_indiff = first.with_indifferent_access | |
second_indiff = second.with_indifferent_access | |
first_faster_indiff = first.with_faster_indifferent_access | |
second_faster_indiff = second.with_faster_indifferent_access | |
tests = 10_000 | |
Benchmark.bmbm do |results| | |
results.report("Hash#faster_diff") { tests.times { first.faster_diff( second ) } } | |
results.report("Hash#diff") { tests.times { first.diff( second ) } } | |
results.report("Hash#faster_deep_merge") { tests.times { first.faster_deep_merge( second ) } } | |
results.report("Hash#deep_merge") { tests.times { first.deep_merge( second ) } } | |
results.report("FasterHashWithIndifferentAccess#to_hash") { tests.times { first_faster_indiff.to_hash } } | |
results.report("HashWithIndifferentAccess#to_hash") { tests.times { first_indiff.to_hash } } | |
results.report("Hash#faster_reverse_merge!") { tests.times { first.faster_reverse_merge!( second ) } } | |
results.report("Hash#reverse_merge!") { tests.times { first.reverse_merge!( second ) } } | |
results.report("HashWithIndifferentAccess#reverse_merge!") { tests.times { first_indiff.reverse_merge!( second ) } } | |
end | |
=begin | |
macbook-pros-computer:~ lourens$ ruby as_bench.rb | |
Rehearsal ---------------------------------------------------------------------------- | |
Hash#faster_diff 0.100000 0.000000 0.100000 ( 0.103207) | |
Hash#diff 0.120000 0.000000 0.120000 ( 0.118790) | |
Hash#faster_deep_merge 0.030000 0.000000 0.030000 ( 0.027385) | |
Hash#deep_merge 0.030000 0.000000 0.030000 ( 0.032819) | |
FasterHashWithIndifferentAccess#to_hash 0.030000 0.000000 0.030000 ( 0.027202) | |
HashWithIndifferentAccess#to_hash 0.030000 0.000000 0.030000 ( 0.032386) | |
Hash#faster_reverse_merge! 0.030000 0.000000 0.030000 ( 0.032605) | |
Hash#reverse_merge! 0.040000 0.000000 0.040000 ( 0.045057) | |
HashWithIndifferentAccess#reverse_merge! 0.360000 0.000000 0.360000 ( 0.362077) | |
------------------------------------------------------------------- total: 0.770000sec | |
user system total real | |
Hash#faster_diff 0.110000 0.000000 0.110000 ( 0.119254) | |
Hash#diff 0.130000 0.000000 0.130000 ( 0.137511) | |
Hash#faster_deep_merge 0.070000 0.000000 0.070000 ( 0.066942) | |
Hash#deep_merge 0.080000 0.000000 0.080000 ( 0.082390) | |
FasterHashWithIndifferentAccess#to_hash 0.020000 0.000000 0.020000 ( 0.021975) | |
HashWithIndifferentAccess#to_hash 0.030000 0.000000 0.030000 ( 0.034503) | |
Hash#faster_reverse_merge! 0.030000 0.000000 0.030000 ( 0.025488) | |
Hash#reverse_merge! 0.040000 0.000000 0.040000 ( 0.044840) | |
HashWithIndifferentAccess#reverse_merge! 0.350000 0.000000 0.350000 ( 0.352209) | |
=end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment