Hash#sum

Updated April 22, 2026 · Hash Methods
hash enumerable sum ruby

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