There are many different methods that allow mapping an Array to a Hash in Ruby.
Array#to_h
with a block (Ruby 2.6+)
You can call an array with a block that is called with each element. The block must return a [key, value]
tuple.
This is useful if both the hash key and value can be derived from each array element:
users = User.all
user_names_by_id = users.to_h { |user| [user.id, user.name] }
{
1 => "Alice",
2 => "Bob"
}
Array#to_h
on an array of key/value tuples (Ruby 2.1+)
Converts an Array of [key, value]
tuples into a Hash.
users = User.all
user_names_by_id = users.map { |user| [user.id, user.name] }.to_h
{
1 => "Alice",
2 => "Bob"
}
Enumerable#index_by
(any Rails version)
users = User.all
users_by_id = users.index_by(&:id)
{
1 => #<User id: 1, name: "Alice">,
2 => #<User id: 2, name: "Bob">
}
In case of a duplicate, the last entry wins.
Enumerable#group_by
(Ruby 1.8.7+)
Use
group_by
Show archive.org snapshot
when duplicates are possible.
Hash values are always an Array of elements per group.
users = User.all
users_by_name = users.group_by(&:name)
{
"Alice" => [#<User id: 1, name: "Alice">],
"Bob" => [#<User id: 2, name: "Bob">]
}
Enumerable#index_with
(Rails 6+)
To generate a hash where array elements become hash keys, and values are calculated from them, use index_with
.
users = User.all
user_ids_by_user = users.index_with(&:name)
{
#<User id: 1, name: "Alice"> => "Alice",
#<User id: 2, name: "Bob"> => "Bob"
}
Legacy solution: collect_hash
monkey patch
The attached initializer will let you create a hash from an array in a single method call.
- Copy the attached initializer to
config/initializers
- All enumerables (arrays, sets, scopes, etc.) now have an additional method
collect_hash
- The method takes a block. The block is called for each element in the array and should return a 2-tuple where the first element is the key and the second element is the value.
- A key/value entry is skipped when the block returns nil.
Example
The following will turn a list of User
records into a hash where the keys are the users' ids and the values are the users' attribute hashes:
users = User.all
user_plans = users.collect_hash do |u|
[u.id, u.attributes]
end