Skip to content

Instantly share code, notes, and snippets.

@kotp
Last active December 11, 2019 01:24
Show Gist options
  • Save kotp/7628cf7a4745c9179c66 to your computer and use it in GitHub Desktop.
Save kotp/7628cf7a4745c9179c66 to your computer and use it in GitHub Desktop.
Build #Hash with #Derivative Value
=begin
Method returns hash of derivitave values as provided.
Example usage:
doctest: Setup
>> require './build_hash_with_derived_values'
=> true
doctest: Yardstick test derived result
>> yardstick = build_hash_with_derivative_values [:yard, :foot, :inch],
[ 1, 3, 12 ]
=> {:inch=>36, :foot=>3, :yard=>1}
doctest: How many inches in 1.5 feet?
We can remember how to do this if we remember that inches in something means
to divide that something by inches. Then 1.5 of that something (where "of"
means to multiply).
>> yardstick[:inch] / yardstick[:foot] * 1.5
=> 18.0
doctest: Units that make up a yard
>> yardstick.keys
=> [:yard, :foot, :inch]
doctest: Units in Year derived result
>> Units_In_One_Year =
build_hash_with_derivative_values [:year, :day, :hour, :minute, :second],
[ 1, 365, 24, 60, 60]
=> {:second=>31536000, :minute=>525600, :hour=>8760, :day=>365, :year=>1}
=end
def build_hash_with_derivative_values units, property
decrement = 0 ; value = nil # house keeping for the hash assignment
hash = {}
hash = units.inject do |key|
(units.size - decrement ).times do |i|
value = 1 unless value # This is opposite of the x ||= value idiom
value = property[i] * value
hash[units[decrement]] = value
decrement += 1 # control the map of the supplied value array.
end
value = nil
hash # this is returned internally to inject.
end
# hash as created by the inect method is returned.
end
@kotp
Copy link
Author

kotp commented Jul 3, 2010

That is pretty cool...

@kotp
Copy link
Author

kotp commented Jul 3, 2010

Jerry Anning had realized that my original code above (specifically version https://gist.github.com/7628cf7a4745c9179c66/4e40a35942c60d97bdf3fb1259ad7a82fd31dab8 ) passes the test if I comment the inject line, and the appropriate 'end'... which means that I basically built something that does both lines:
properties = property.inject([1]) { |a,v| a << v*a[-1] }
units.zip(properties).inject({}) { |h, (k,v)| h[k] = v ; h }

@citizen428
Copy link

Victor: I didn't think your original solution was bad, it's readable and does what it's supposed to do. My solution was more a for fun approach and because you asked me on IRC re inject. Given that my main interest nowadays is functional programming, I tend to use the likes of inject, map, zip, etc. a lot. I even have a project here on GH that's supposed to one day become an ebook on functional programming in Ruby, alas I never have enough time for all my different projects...

@kotp
Copy link
Author

kotp commented Jul 3, 2010

Thank you... The reason I asked for inject, is because it is way over due that I actually understand how inject works, past the trivial (though mystical) (1..5).inject(:+) invocation, or the written out (1..5).inject { |sum, n| sum + n }

I thank you tons for your solution, because it gave me something more complex to look at, while realizing that my code did the same thing, and gave me more area to understand in the novelty of that small space, and something to compare the behavior and activity with.

I really didn't take it as an opinion on my original solution. I just knew that it 'looked' like it was doing something that could be done differently.

I actually have about 4 different solutions, all that pass the doctests and it will be interesting to see which is more efficient in terms of benchmarks, and profiler measurements. I wish I programmed every day... actually with people, because it is times like these that I learn the most. I only have certain viewpoints, and I stretch them, but it helps to have other eyes on the matter too.

It is why I like working with you guys.

@citizen428
Copy link

Funny that you bring up (1..5).inject(&:+), since it always struck me as a particularly bad example, since summing the numbers from 1 to n is most efficiently done as (n*(n+1))/2 (http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/runsums/triNbProof.html). A couple of days ago I actually benchmarked it because I was thinking about a blog post called "Why knowing your math helps" and the second solution was considerably faster than inject.

BTW: the written out form of your inject would just return 5, what you meant is (1..5).inject { |sum, n| sum + n }

@kotp
Copy link
Author

kotp commented Dec 11, 2019

Does math always win out over inject/iterations? I can't think of a situation where it wouldn't, but then I am not a math nerd.

Also, happy holidays to wherever both are!

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