Created
January 14, 2009 06:38
-
-
Save heycarsten/46819 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
# Self-If-Self: A Study | |
# | |
# I have decided that this is silly, but I want to share it to see what other | |
# people think. | |
# | |
require 'benchmark' | |
require 'pp' | |
class Object | |
def if | |
yield(self) if self | |
end | |
end | |
update_with_flat_person = { | |
:person_name => 'Carsten', | |
:person_id => 23, | |
:text => 'Known to be quirky at times.' } | |
update_with_actual_person = { | |
:person => { | |
:name => 'Carsten', | |
:id => 23 }, | |
:text => 'Known to be quirky at times.' } | |
# This would be normal | |
def build(attributes) | |
person = attributes.delete(:person) | |
if person | |
attributes[:person_id] = person[:id] | |
attributes[:person_name] = person[:name] | |
end | |
attributes | |
end | |
pp build(update_with_actual_person) | |
# And this would be one of my crack-pot delusions... | |
def self_if_self_build(attributes) | |
attributes.delete(:person).if do |person| | |
attributes[:person_id] = person[:id] | |
attributes[:person_name] = person[:name] | |
end | |
attributes | |
end | |
pp self_if_self_build(update_with_actual_person) | |
# The normal approach is almost two times faster than the self-if-self | |
# monkeypatch magic on a 2.2 GHz MacBook Pro with 4 GB of RAM. | |
# | |
# The actual numbers on my machine: | |
# user system total real | |
# Normal Approach 4.540000 1.940000 6.480000 ( 6.497931) | |
# Self-If-Self Monkeypatch 8.300000 3.870000 12.170000 ( 12.207854) | |
# | |
Benchmark.bmbm do |b| | |
b.report('Normal Approach') do | |
500_000.times { build update_with_flat_person } | |
500_000.times { build update_with_actual_person } | |
end | |
b.report('Self-If-Self Monkeypatch') do | |
500_000.times { self_if_self_build update_with_flat_person } | |
500_000.times { self_if_self_build update_with_actual_person } | |
end | |
end | |
# Perhaps a better approach (at least in this case) | |
def inject_flatten(hsh, target, target_keys) | |
hsh.keys.inject({}) do |output, key| | |
if target == key | |
target_keys.each { |k| output[:"#{target}_#{k}"] = hsh[target][k] } | |
else | |
output[key] = hsh[key] | |
end | |
output | |
end | |
end | |
def inject_flatten_build(attributes) | |
inject_flatten attributes, :person, [:id, :name] | |
end | |
pp inject_flatten_build(update_with_actual_person) | |
# This one is curious as well, sure looks easier to read | |
def dup_flatten(hsh, target_key, target_keys) | |
result = hsh.dup | |
target = result.delete(target_key) | |
target_keys.each { |k| result[:"#{target_key}_#{k}"] = target[k] } if target | |
result | |
end | |
def dup_flatten_build(attributes) | |
dup_flatten attributes, :person, [:id, :name] | |
end | |
pp dup_flatten_build(update_with_actual_person) | |
# The inject_flatten approach seems pretty inefficient (duh.) | |
# | |
# user system total real | |
# Inject Flatten 36.560000 14.600000 51.160000 ( 51.558791) | |
# Copy Flatten 11.840000 3.900000 15.740000 ( 15.830560) | |
# | |
Benchmark.bmbm do |b| | |
b.report('Inject Flatten') do | |
500_000.times { inject_flatten_build update_with_flat_person } | |
500_000.times { inject_flatten_build update_with_actual_person } | |
end | |
b.report('Copy Flatten') do | |
500_000.times { dup_flatten_build update_with_flat_person } | |
500_000.times { dup_flatten_build update_with_actual_person } | |
end | |
end | |
# What if we do it in-place? | |
def in_place_flatten(hsh, target_key, target_keys) | |
target = hsh.delete(target_key) | |
target_keys.each { |k| hsh[:"#{target_key}_#{k}"] = target[k] } if target | |
hsh | |
end | |
def in_place_flatten_build(attributes) | |
in_place_flatten attributes, :person, [:id, :name] | |
end | |
pp in_place_flatten_build(update_with_actual_person) | |
# A lot faster, but modifying arguments can really bite you. | |
# | |
# user system total real | |
# In-Place Flatten 7.260000 2.940000 10.200000 ( 10.212538) | |
# | |
Benchmark.bmbm do |b| | |
b.report('In-Place Flatten') do | |
500_000.times { in_place_flatten_build update_with_flat_person } | |
500_000.times { in_place_flatten_build update_with_actual_person } | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment