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.
我似乎经常碰到这个。我需要使用数组中每个对象的属性作为键从数组构建一个Hash。
Lets say I need a hash of example uses ActiveRecord objecs keyed by their ids Common way:
让我说我需要一个示例哈希使用ActiveRecord objecs键入他们的ID常见方式:
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?
Dream Way:我可以并且可能自己创建这个,但Ruby或Rails中有什么东西可以吗?
ary = [collection of ActiveRecord objects]
hash = ary.to_hash &:id
#or at least
hash = ary.to_hash {|obj| obj.id}
5 个解决方案
#1
52
There is already a method in ActiveSupport that does this.
ActiveSupport中已有一种方法可以执行此操作。
['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
#2
9
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
#3
5
You can add to_hash to Array yourself.
您可以自己将to_hash添加到Array。
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
#4
5
In case someone got plain array
万一有人得到普通阵列
arr = ["banana", "apple"]
Hash[arr.map.with_index.to_a]
=> {"banana"=>0, "apple"=>1}
#1
52
There is already a method in ActiveSupport that does this.
ActiveSupport中已有一种方法可以执行此操作。
['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
#2
9
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
#3
5
You can add to_hash to Array yourself.
您可以自己将to_hash添加到Array。
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
#4
5
In case someone got plain array
万一有人得到普通阵列
arr = ["banana", "apple"]
Hash[arr.map.with_index.to_a]
=> {"banana"=>0, "apple"=>1}