Cleanest way to create a Hash from an Array

41,583

Solution 1

There is already a method in ActiveSupport that does this.

['an array', 'of active record', 'objects'].index_by(&:id)

And just for the record, here's the implementation:

def index_by
  inject({}) do |accum, elem|
    accum[yield(elem)] = elem
    accum
  end
end

Which could have been refactored into (if you're desperate for one-liners):

def index_by
  inject({}) {|hash, elem| hash.merge!(yield(elem) => elem) }
end

Solution 2

a shortest one?

# 'Region' is a sample class here
# you can put 'self.to_hash' method into any class you like 

class Region < ActiveRecord::Base
  def self.to_hash
    Hash[*all.map{ |x| [x.id, x] }.flatten]
  end
end

Solution 3

In case someone got plain array

arr = ["banana", "apple"]
Hash[arr.map.with_index.to_a]
 => {"banana"=>0, "apple"=>1}

Solution 4

You can add to_hash to Array yourself.

class Array
  def to_hash(&block)
    Hash[*self.map {|e| [block.call(e), e] }.flatten]
  end
end

ary = [collection of ActiveRecord objects]
ary.to_hash do |element|
  element.id
end
Share:
41,583
Daniel Beardsley
Author by

Daniel Beardsley

I'm an independent Web Developer located on the Central Coast of California. I mostly develop using Ruby on Rails, but have been trying out Sinatra, Node.js, and other fun things as of late.

Updated on March 11, 2020

Comments

  • Daniel Beardsley
    Daniel Beardsley about 4 years

    I seem to run into this very often. I need to build a Hash from an array using an attribute of each object in the array as the key.

    Lets say I need a hash of example uses ActiveRecord objecs keyed by their ids Common way:

    ary = [collection of ActiveRecord objects]
    hash = ary.inject({}) {|hash, obj| hash[obj.id] = obj }
    

    Another Way:

    ary = [collection of ActiveRecord objects]
    hash = Hash[*(ary.map {|obj| [obj.id, obj]}).flatten]
    

    Dream Way: I could and might create this myself, but is there anything in Ruby or Rails that will this?

    ary = [collection of ActiveRecord objects]
    hash = ary.to_hash &:id
    #or at least
    hash = ary.to_hash {|obj| obj.id}