Convert An Array Of Hashes Into A Grouped Hash By A Key In Ruby
Transform a flat array of hashes into a hash where each key maps to an array of matching records — the core operation for grouping, summarizing, and pivoting collections.
Description
Enumerable#group_by groups elements by the block’s return value into a hash. Combined with transform_values you can then aggregate, count, or reshape each group.
Common pattern: group records by a category field, then transform each group into a count, a sum, or a list of a specific attribute.
Sample input:
orders = [
{ id: 1, status: :paid, amount: 100 },
{ id: 2, status: :pending, amount: 50 },
{ id: 3, status: :paid, amount: 200 },
{ id: 4, status: :pending, amount: 75 }
]
Sample Output:
{ paid: [100, 200], pending: [50, 75] }
Answer
orders = [
{ id: 1, status: :paid, amount: 100 },
{ id: 2, status: :pending, amount: 50 },
{ id: 3, status: :paid, amount: 200 },
{ id: 4, status: :pending, amount: 75 }
]
# Group by status — returns hash of status => [full hashes]
orders.group_by { |o| o[:status] }
# => { paid: [{id:1,...}, {id:3,...}], pending: [{id:2,...}, {id:4,...}] }
# Group then pluck amounts
orders.group_by { |o| o[:status] }
.transform_values { |group| group.map { |o| o[:amount] } }
# => { paid: [100, 200], pending: [50, 75] }
# Group then sum amounts
orders.group_by { |o| o[:status] }
.transform_values { |group| group.sum { |o| o[:amount] } }
# => { paid: 300, pending: 125 }
# Group then count
orders.group_by { |o| o[:status] }
.transform_values(&:count)
# => { paid: 2, pending: 2 }
# Tally (Ruby 2.7+) for count-only grouping
orders.tally_by { |o| o[:status] } # Not built-in, but:
orders.map { |o| o[:status] }.tally
# => { paid: 2, pending: 2 }
Check viewARU - Brand Newsletter!
Newsletter to DEVs by DEVs - boost your Personal Brand & career! 🚀