Hash#sum
Hash#sum is defined in the Enumerable module, which Hash includes. It totals values — either by adding key-value pairs directly, or by summing whatever your block returns.
Basic Usage
With a block, you get proper key and value parameters:
scores = { alice: 95, bob: 82, carol: 98 }
scores.sum { |_name, score| score }
# => 275
The block gets called once per key-value pair, with key as the first argument and value as the second.
Shorthand with Symbol#to_proc
When you’re summing a single value from each pair, the &:method shorthand works:
prices = { "Widget" => 12.99, "Gadget" => 24.99, "Doodad" => 7.99 }
prices.sum(&:last)
# => 45.97
&:last calls .last on each [key, value] pair — which returns the value. Exactly what you need.
Summing with Initial Value
Pass an initial value as the first argument:
scores.sum(100)
# Without block: 100 + [:alice, 95] + [:bob, 82] + [:carol, 98]
# => raises TypeError (can't add Integer + Array)
The initial value approach is only useful with a block:
scores.sum(10) { |_name, score| score }
# => 10 + 95 + 82 + 98 = 285
Without a Block
sum without a block iterates over key-value pairs as 2-element arrays and adds them together:
{a: 1, b: 2}.sum
# => [:a, 1, :b, 2] — arrays concatenated, not values summed
This only makes sense when the concatenation itself is meaningful, or when all values are Integer (because [1, 2] + [3, 4] = [1, 2, 3, 4] and [1] + [2] = [1, 2]). For summing numeric values, always use a block.
Using Blocks for Conditional Summing
The block gives you full control over what gets summed:
users = { alice: 28, bob: 17, carol: 35, dave: 22 }
# Sum only adults
users.sum(0) { |_name, age| age >= 18 ? age : 0 }
# => 85 (28 + 35 + 22)
Without 0 as initial value, the block approach still works because numbers have a natural sum:
users.sum { |_name, age| age >= 18 ? age : 0 }
# => 85
Strings and Arrays
sum works with any objects that respond to +:
words = { a: "cat", b: "dog", c: "bat" }
words.sum("") { |_k, v| v }
# => "catdogbat"
The initial value "" gets the concatenation started.
Empty Hash
sum on an empty hash returns the initial value:
{}.sum
# => 0 (default initial value)
{}.sum(10)
# => 10
{}.sum(0) { |_k, v| v }
# => 0
Why Not Use Each or Reduce?
You could write the same thing with each_with_object:
scores.each_with_object(0) { |(_name, score), total| total + score }
sum with a block is cleaner and more direct. Under the hood, it’s optimized with a C implementation that avoids the slower inject/reduce path when possible.
Gotchas
Without a block, sum on a hash concatenates arrays, not values:
{ a: 1, b: 2 }.sum # => [:a, 1, :b, 2] not 3
If you want the values, use a block.
Float precision: summing many floats can accumulate rounding errors. For financial calculations, use BigDecimal or a specialized library.
Strings are slow with sum: 'a'..'z').sum works but is O(n^2) because strings are immutable and each + creates a new string. Use join instead.
See Also
- /reference/hash-methods/hash-min-by/ — finding minimums with a block
- /reference/enumerable/enumerable-sum/ — the full Enumerable#sum reference
- /guides/ruby-working-with-hashes/ — practical patterns for hash manipulation