Hey, it’s Friday. Let’s play with hashes.
First up: how to build a hash from an array? Fairly straightforward. Make sure your array is in the format of [‘name’, ‘chris’, ‘age’, 47] then just pass it to Hash[] with a splat.
>> array = ["name", "chris", "age", 47] => ["name", "chris", "age", 47] >> Hash[*array] => {"name"=>"chris", "age"=>47}
The splat (asterix) expands the elements of the array into method parameters. Right? Our Hash[*array] call is then interpreted as something akin to
Hash[“name”, “chris”, “age”, 47].
Which is how Hash[] likes it.
Do me a favor. Throw a flatten in there so you can pass nested arrays.
>> array = [["name", "chris"], ["age", 47]] => [["name", "chris"], ["age", 47]] >> Hash[*array.flatten] => {"name"=>"chris", "age"=>47}
Now we can bounce back and forth between arrays and hashes all day long.
>> blog = { :name => 'err', :style => 'classic' } => {:name=>"err", :style=>"classic"} >> blog.to_a => [[:name, "err"], [:style, "classic"]] >> Hash[*blog.to_a.flatten] => {:name=>"err", :style=>"classic"}
Hey, put it in your pocket and take it with you.
class Array def to_hash Hash[*self.flatten] end alias :to_h :to_hash end >> [[:name, "err"], [:style, "classic"]].to_h => {:name=>"err", :style=>"classic"}
We agreed it’s Friday, right? Right. And we all know Friday is a lazy day. So, have some fun with hash default values.
>> animals = Hash.new('Not an animal.') => {} >> animals[:dog] = "An animal!" => "An animal!" >> animals[:bug] => "Not an animal." >> animals[:dog] => "An animal!"
Them’s the basics. You can also pass Hash.new a block, which is where it gets interesting. The hash itself and the key trying to be accessed are both slide into the called block on a hash lookup failure.
Let’s initialize elements to an array on lookup miss:
>> hash_of_arrays = Hash.new { |hash, key| hash[key] = [] } => {} >> hash_of_arrays[:animals] << 'Dog' => ["Dog"] >> hash_of_arrays[:animals] => ["Dog"]
Wow. That is super lazy. Careful, though, as any misses will become empty elements of the hash.
>> hash_of_arrays = Hash.new { |hash, key| hash[key] = [] } => {} >> hash_of_arrays.keys => [] >> hash_of_arrays[:dog] => [] >> hash_of_arrays.keys => [:dog]
This trick is also useful for figuring out “did I do something already?” Observe:
>> actions = Hash.new { |hash, key| hash[key] = true; false } => {} >> actions[:move] => false >> actions[:move] => true
We’re setting the element to true but returning false on the first hit. Now we can construct some logic like:
unless @actions[:deleted] object.delete else raise "Already deleted!" end
You’re more creative than I am. I’m sure you’ll find a cool use.
Man, too much code for a Friday. But nothing revolutionary. You can find these kind of tricks on Code Snippets or out in the blogosphere. Have a nice weekend. Friend.
Awesome! Keep it up. I’m already looking forward to next Friday’s installment!
The Hash[*array] trick is great for mapping a hash into another hash:
Great stuff … I just stumbled across this blog (6May2008)
Chime in.