Err the Blog Atom Feed Icon
Err the Blog
Rubyisms and Railities
  • “Friday Hash Fun”
    – Chris on August 18, 2006

    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.

  • Kevin Marsh, about 12 hours later:

    Awesome! Keep it up. I’m already looking forward to next Friday’s installment!

  • Tore Darell, 9 days later:

    The Hash[*array] trick is great for mapping a hash into another hash:

    >> Hash[*{1 => 'one', 2 => 'two'}.map{|k,v| [k.succ, v.succ] }.flatten]
    => {2=>"onf", 3=>"twp"}
    
  • Richard Muller, about 1 year later:

    Great stuff … I just stumbled across this blog (6May2008)

  • Three people have commented.
    Chime in.
    Sorry, no more comments :(
This is Err, the weblog of PJ Hyett and Chris Wanstrath.
All original content copyright ©2006-2008 the aforementioned.