Array#sum
The .sum method calculates the total of all elements in an array. It is part of the Enumerable module, so it works on arrays, ranges, and hashes. Ruby added this method in version 2.4 to provide a simpler alternative to inject(:+) for common summation tasks.
# Basic usage
numbers = [1, 2, 3, 4, 5]
numbers.sum
# => 15
# With initial value
numbers.sum(10)
# => 25
# With ranges
(1..100).sum
# => 5050
That first block shows the default behavior, the optional starting value, and a range example in one place. In practice, sum is handy whenever you want a readable shortcut for accumulation, especially when the block or the starting value makes the intent clearer than a manual loop. It also keeps the example focused on the result instead of on the mechanics of the loop.
Syntax
array.sum
array.sum(initial)
array.sum(initial) { |element| block }
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
initial | Object | 0 (for numbers) | Starting value for the sum. Defaults to zero for numeric arrays, empty string for string arrays. |
| block | Block | None | Optional block to transform each element before summing. |
What .sum Returns
.sum returns the total as a number by default. The return type matches the input type plus the initial value:
[1, 2, 3].sum
# => 6 (Integer)
[1.5, 2.5, 3.0].sum
# => 7.0 (Float)
The return type follows Ruby’s standard numeric coercion rules: adding integers yields an integer, and mixing an integer with a float promotes the result to float. The initial value also influences the return type, so [1, 2].sum(0.0) produces a float even when the array is all integers.
Examples
Basic numeric summation
prices = [29.99, 14.99, 9.99, 49.99]
prices.sum
# => 104.96
# Sum of a range
(1..1000).sum
# => 500500
With initial value
The initial value lets you offset the sum or use it as an accumulator for more complex operations. It is useful when your calculation needs a non-zero starting point, or when you want to carry a running total across several related values.
# Start from a different number
[1, 2, 3].sum(10)
# => 16
# Accumulate across multiple arrays
total = [1, 2, 3].sum
total += [4, 5, 6].sum
total += [7, 8, 9].sum
# => 45
This pattern is common in reporting code, where a subtotal begins at a known baseline and each group adds on top of it. The extra argument keeps that intent visible at the call site. It is also helpful when the first value should not be treated specially, because the starting number makes the calculation explicit.
With 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)
# With initial value and block
(1..4).sum(100) { |i| i * i }
# => 130 (100 + 1 + 4 + 9 + 16)
Blocks are useful when the raw values are not the values you want to add. You can filter, square, or normalize each element before the final total is calculated.
That makes the method flexible enough for small calculations without having to switch to a separate mapping step. The block stays local to the sum, which keeps the intent easy to follow.
With Hashes
Hashes need a little extra care because the block receives both the key and the value. That makes it easy to sum only the values, or to mix the key into the calculation when the result depends on both parts.
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 (5 + 85 + 3 + 92 + 5 + 78)
The hash example shows how the block receives both the key and the value, which is the standard Enumerable behavior for hashes. You can sum just the values by ignoring the key with an underscore prefix, or you can incorporate the key into the calculation when the sum depends on both parts of each pair.
With Strings
When you pass a string as the initial value, sum acts like concatenation instead of numeric addition. That is helpful for building a combined label or payload from several pieces of text.
# Concatenate strings
["hello", "world"].sum("")
# => "helloworld"
# With initial string
["a", "b", "c"].sum("prefix-")
# => "prefix-abc"
# With block
["cat", "dog", "bird"].sum("") { |word| word[0].to_s }
# => "cdb" (first character of each)
When the initial value is a string, sum concatenates rather than adding numbers. This is a convenient shortcut when you want to join a collection of strings with an optional prefix. For more complex join operations with separators, Array#join is usually a better fit, but sum works well when you are building a simple combined string from pieces that do not need a delimiter.
Common Patterns
Calculating Averages
Combine .sum with .count to calculate averages:
grades = [85, 90, 78, 92, 88]
average = grades.sum / grades.count
# => 86
The average calculation pairs sum with count, two methods that read naturally together. Because both operate on the same collection, the code stays clear even when the data source changes. For floating-point averages, remember that integer division truncates, so cast one operand to Float when decimals matter.
Conditional Sum
Use a block to sum only matching elements:
transactions = [100, -50, 200, -25, 150]
# Sum only positive transactions
income = transactions.sum { |t| t > 0 ? t : 0 }
# => 450
# Sum only negative (expenses)
expenses = transactions.sum { |t| t < 0 ? t : 0 }
# => -75
The conditional sum pattern keeps the filtering logic inside the block, so you do not need a separate select or reject pass. The block returns 0 for elements you want to skip, which preserves the sum without introducing conditional branching outside the method call.
Weighted Sums
values = [10, 20, 30]
weights = [0.5, 0.3, 0.2]
weighted_sum = values.map.with_index { |v, i| v * weights[i] }.sum
# => 17.0
Weighted sums are common in scoring algorithms, grade calculations, and statistical transforms. By pairing map.with_index with sum, you get a clear pipeline: the map pairs each value with its weight, and the sum collapses everything into a single result.
Performance
The .sum method has built-in optimizations. For consecutive integer ranges, Ruby uses Gauss’s summation formula:
# Ruby optimizes this to n(n+1)/2
(1..1000000).sum
# => 500000500000 (instant, not a loop)
For large arrays of numbers, .sum is faster than inject(:+) because it bypasses some of the Enumerable overhead.
That performance difference is usually minor in small scripts, but it becomes easier to notice in tight loops or larger data sets. When the task is straightforward addition, sum is the method Ruby wants you to reach for first.
Gotchas
Empty arrays return initial value
[].sum
# => 0
[].sum(100)
# => 100
Calling sum on an empty collection always returns the initial value, which defaults to 0 for numeric arrays. This is a safe default that keeps downstream arithmetic from breaking on nil, but it also means you cannot distinguish an empty array from one whose elements sum to zero just by checking the return value.
Float Precision
[0.1, 0.2].sum
# => 0.30000000000000004 (floating point quirk)
Floating-point arithmetic follows IEEE 754 rules, so adding 0.1 and 0.2 produces the same small rounding artifact you would see in any language. When exact decimal precision matters, consider using BigDecimal or Rational instead of Float for the values being summed.
Block overrides initial for first element
When using a block, the initial value is still 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
See Also
.inject / .reduce— More flexible accumulation method.map— Transform elements before summing.count— Count elements matching a condition