Enumerable#sum
The sum method adds together all elements in a collection. It is part of the Enumerable module, available on arrays, ranges, hashes, and any object that includes Enumerable. Ruby introduced this method in version 2.4 to provide a simpler, more readable alternative to reduce(:+) for common summation tasks.
[1, 2, 3, 4, 5].sum
# => 15
(1..5).sum
# => 15
Syntax
collection.sum
collection.sum(initial)
collection.sum { |element| block }
collection.sum(initial) { |element| block }
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
initial | Object | 0 | Starting value added to the sum. For numbers this defaults to zero. |
| block | Block | None | Optional block to transform each element before summing. |
Basic Usage
Summing Numbers
The most common use case is adding up numbers:
prices = [29.99, 14.99, 9.99, 49.99]
prices.sum
# => 104.96
# Sum of a range
(1..100).sum
# => 5050
With Initial Value
Pass an initial value to start the sum from a different number:
[1, 2, 3].sum(10)
# => 16
# Useful for accumulating across multiple collections
total = [1, 2, 3].sum
total += [4, 5, 6].sum
total += [7, 8, 9].sum
# => 45
Empty Collections
For an empty collection, sum returns the initial value (zero by default):
[].sum
# => 0
[].sum(100)
# => 100
Using a Block
Pass a block to transform elements before summing:
# Square each number before summing
(1..4).sum { |i| i * i }
# => 30 (1 + 4 + 9 + 16)
# Sum only even numbers
(1..10).sum { |n| n.even? ? n : 0 }
# => 30 (2 + 4 + 6 + 8 + 10)
# Initial value with block
(1..4).sum(100) { |i| i * i }
# => 130 (100 + 1 + 4 + 9 + 16)
Block Semantics with Initial Value
When using both an initial value and a block, the initial value is added once at the end, not used as the starting accumulator:
[1, 2, 3].sum(10) { |n| n * 2 }
# => 10 + (1*2 + 2*2 + 3*2) = 10 + 12 = 22
With Hashes
scores = { alice: 85, bob: 92, carol: 78 }
# Sum values
scores.sum { |_name, score| score }
# => 255
# Sum with transformation
scores.sum(0) { |name, score| name.to_s.length + score }
# => 266 (length of :alice (5) + 85 + length of :bob (3) + 92 + length of :carol (5) + 78)
With Strings
# Concatenate strings
["hello", "world"].sum("")
# => "helloworld"
# With initial string
["a", "b", "c"].sum("prefix-")
# => "prefix-abc"
# With block - take first character of each
["cat", "dog", "bird"].sum("") { |word| word[0].to_s }
# => "cdb"
Difference from inject/reduce
sum is specialized for addition, making it more readable than reduce for simple summation:
# Using reduce
[1, 2, 3].reduce(0, :+)
# => 6
# Using sum (cleaner)
[1, 2, 3].sum
# => 6
Key differences:
| Aspect | sum | reduce |
|---|---|---|
| Purpose | Specifically for addition | General accumulation |
| Readability | Intuitive for sums | More flexible but verbose |
| Performance | Optimized for numeric sums | General purpose overhead |
| Initial value default | 0 for numbers | Must be specified |
Floating Point Precision
Like all floating point arithmetic, sum inherits precision limitations:
[0.1, 0.2].sum
# => 0.30000000000000004
# For precise decimal arithmetic, use BigDecimal:
require 'bigdecimal'
[BigDecimal("0.1"), BigDecimal("0.2")].sum
# => 0.3
Practical Examples
Calculating Averages
Combine sum with count to calculate averages:
grades = [85, 90, 78, 92, 88]
average = grades.sum / grades.count
# => 86
Conditional Sum
Sum only elements matching a condition:
transactions = [100, -50, 200, -25, 150]
# Sum only positive transactions (income)
income = transactions.sum { |t| t > 0 ? t : 0 }
# => 450
# Sum only negative transactions (expenses)
expenses = transactions.sum { |t| t < 0 ? t : 0 }
# => -75
Totaling Prices with Tax
prices = [19.99, 29.99, 9.99]
tax_rate = 0.08
total_with_tax = prices.sum { |price| price * (1 + tax_rate) }
# => 64.57 (rounded display: $%.2f' % 64.57)
Counting Items by Category
inventory = [
{ item: "Apple", quantity: 50, price: 0.50 },
{ item: "Banana", quantity: 100, price: 0.20 },
{ item: "Orange", quantity: 75, price: 0.60 }
]
# Total inventory value
total_value = inventory.sum { |i| i[:quantity] * i[:price] }
# => 95.0
Summing Nested Arrays
matrix = [[1, 2], [3, 4], [5, 6]]
# Sum all elements
matrix.sum { |row| row.sum }
# => 21
# Sum with flatten
matrix.flatten.sum
# => 21
Performance Notes
sum has built-in optimizations for common cases:
# Ruby optimizes consecutive integer ranges using Gauss's formula
(1..1000000).sum
# => 500000500000 (instant, not a loop)
# For arrays of numbers, sum is faster than reduce(:+)
# because it avoids some Enumerable overhead
Return Value
sum returns the accumulated total:
- Numbers: returns an Integer or Float depending on inputs
- Strings: returns a concatenated String
- Empty collection with default: returns
0 - Empty collection with initial: returns that initial value
Edge Cases
# Single element
[5].sum
# => 5
# Single element with initial
[5].sum(10)
# => 15
# All zero values
[0, 0, 0].sum
# => 0
# Mixed positive and negative
[-10, 5, 3, -2].sum
# => -4
See Also
Enumerable#reduce— General-purpose accumulation methodEnumerable#inject— Alias for reduceEnumerable#select— Filter elements before summingEnumerable#map— Transform elements before summing