Array#to_h

I found myself writing something like this far too often:

def map_something(array)
  hash = {}
  array.each do |a|
    hash[a] = lookup_value a
  end
  hash
end

It bugged me every time, but digging through the Pick Axe never yielded (ahem) a simpler solution. What I wanted to do is this:

def map_something(array)
  array.to_h do |a|
    lookup_value a
  end
end

But of course you'd need Array#to_h. Here's the cleverest implementation I could think of.

class Array
  def to_h(default=nil)
    Hash[ *inject([]) { |a, value| a.push value, default || yield(value) } ]
  end
end

A pointless example:

a = [1, 2, 3]
a.to_h do |v|
  [v * 2, v * 3]
end
> {1=>[2, 3], 2=>[4, 6], 3=>[6, 9]}

I love Array#inject!

  • May 20, 2005
  • Dealing with ruby

There are 5 comments

  1. About 5 hours later, Frederick Ros said...

    And what about :

    class Array
       def to_h(default=nil)
         inject({}) {|h,value| h[value] = default || yield(value); h }
        end
    end
    

    Only slightly different ;)

  2. 1 day later, Peter Cooper said...

    How about this?

    a = [1, 2, 3] Hash[*a.collect { |v| [v, v*2] }.flatten]

    Not quite as clean, but no new methods required.

  3. 1 day later, Peter Cooper said...

    Oops, try this (same, but with nicer formatting):

    a = [1, 2, 3]
    Hash[*a.collect { |v|
        [v, v*2]
    }.flatten]
  4. 1 day later, Ryan Carver said...

    Note that flatten obliterates the nested arrays so you end up with {1=>2, 2=>4, 3=>6}.

    Seems however you do it, it's not something I want to write a lot.. a strange case in Ruby that there's not a really elegant one-liner.

  5. 3 days later, Ulysses said...

    I fond myself building a hash using an object to find a key for it -- like this:

    a = %w(hello world! how are you)
    a.inject({}) {|h, str| h[str.length] = str; h}
    

    So I use

    class Enumerable
      def build_hash
        inject({}) {|h, o| h[yield o] = o; h}
      end
    end
    

    Which is used like

    [1, 2, 3].build_hash {|x| x * 2} #=> {2 => 1, 4 => 2, 6 => 3}