I have a simple array:
arr = ["apples", "bananas", "coconuts", "watermelons"]
I also have a function f
that will perform an operation on a single string input and return a value. This operation is very expensive, so I would like to memoize the results in the hash.
I know I can make the desired hash with something like this:
h = {} arr.each { |a| h[a] = f(a) }
What I'd like to do is not have to initialize h, so that I can just write something like this:
h = arr.(???) { |a| a => f(a) }
Can that be done?
The to_h method is defined in the array class. It works to convert an array to a hash in the form of key-value pairs. The method converts each nested array into key-value pairs. The method also accepts a block.
In Ruby you can create a Hash by assigning a key to a value with => , separate these key/value pairs with commas, and enclose the whole thing with curly braces.
You are allowed to create an array of hashes either by simply initializing array with hashes or by using array. push() to push hashes inside the array. Note: Both “Key” and :Key acts as a key in a hash in ruby.
The pop() function in Ruby is used to pop or remove the last element of the given array and returns the removed elements. Parameters: Elements : This is the number of elements which are to be removed from the end of the given array.
Say you have a function with a funtastic name: "f"
def f(fruit) fruit + "!" end arr = ["apples", "bananas", "coconuts", "watermelons"] h = Hash[ *arr.collect { |v| [ v, f(v) ] }.flatten ]
will give you:
{"watermelons"=>"watermelons!", "bananas"=>"bananas!", "apples"=>"apples!", "coconuts"=>"coconuts!"}
Updated:
As mentioned in the comments, Ruby 1.8.7 introduces a nicer syntax for this:
h = Hash[arr.collect { |v| [v, f(v)] }]
Did some quick, dirty benchmarks on some of the given answers. (These findings may not be exactly identical with yours based on Ruby version, weird caching, etc. but the general results will be similar.)
arr
is a collection of ActiveRecord objects.
Benchmark.measure { 100000.times { Hash[arr.map{ |a| [a.id, a] }] } }
Benchmark @real=0.860651, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.8500000000000005, @total=0.8500000000000005
Benchmark.measure { 100000.times { h = Hash[arr.collect { |v| [v.id, v] }] } }
Benchmark @real=0.74612, @cstime=0.0, @cutime=0.0, @stime=0.010000000000000009, @utime=0.740000000000002, @total=0.750000000000002
Benchmark.measure { 100000.times { hash = {} arr.each { |a| hash[a.id] = a } } }
Benchmark @real=0.627355, @cstime=0.0, @cutime=0.0, @stime=0.010000000000000009, @utime=0.6199999999999974, @total=0.6299999999999975
Benchmark.measure { 100000.times { arr.each_with_object({}) { |v, h| h[v.id] = v } } }
Benchmark @real=1.650568, @cstime=0.0, @cutime=0.0, @stime=0.12999999999999998, @utime=1.51, @total=1.64
Just because Ruby is expressive and dynamic, doesn't mean you should always go for the prettiest solution. The basic each loop was the fastest in creating a hash.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With