Array#inject
inject(initial = nil) { |memo, element| block } -> result inject iterates over an array while maintaining an accumulator value. On each iteration, the block receives the current accumulator (called memo) and the current element. The block return value becomes the new accumulator.
Syntax
array.inject(initial) { |memo, element| block }
array.inject { |memo, element| block }
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| initial | Object | nil | Starting value for the accumulator. If omitted, first element becomes initial. |
The initial value is optional. When provided, it becomes the first memo and iteration starts from the first element. When omitted, the first element becomes the initial memo and iteration starts from the second element. Providing an explicit initial value gives predictable results with empty arrays.
Examples
Summing numbers
numbers = [1, 2, 3, 4, 5]
sum = numbers.inject(0) { |memo, n| memo + n }
puts sum # => 15
sum = numbers.inject { |memo, n| memo + n }
puts sum # => 15
When the initial value is omitted, inject uses the first element of the array as the starting memo. For a sum this works cleanly because the first number just gets added to the second. But when the accumulator shape differs from the element type, providing an explicit initial value is usually clearer and avoids surprises with empty arrays.
Building a hash
items = [:a, :b, :c]
indexed = items.inject({}) do |memo, item|
memo[item] = item.to_s.upcase
memo
end
puts indexed # => {:a=>"A", :b=>"B", :c=>"C"}
Building a collection with inject works by passing the accumulator through each iteration and returning it at the end of the block. The explicit memo at the bottom of the block is the key detail: without it, the block returns only the last expression, which would break the accumulation. This is a common gotcha for newcomers to the method.
Finding maximum
scores = [23, 87, 45, 92, 67]
max = scores.inject do |memo, score|
memo > score ? memo : score
end
puts max # => 92
Tracking a running maximum through inject works because the block decides what to keep on each step. The comparison memo > score ? memo : score carries the larger value forward, so by the time the iteration finishes the memo holds the largest element seen. This same pattern adapts to minimums, longest strings, or any other running comparison.
Common Patterns
# Start from different initial value
result = [1, 2, 3].inject(10) { |memo, n| memo + n }
puts result # => 16
# Chaining
result = [1, 2, 3, 4, 5, 6]
.select(&:even?)
.inject(0) { |memo, n| memo + n }
puts result # => 18
Think of inject as running accumulation
inject is the method you reach for when you want to turn a list of values into one result. That result might be a sum, a joined string, a hash, or some other shape built one step at a time. Because the block receives the current memo and the next element, the method reads like a small accumulation loop with a clear contract. It is especially useful on arrays and other enumerable objects where each item contributes something to the final answer.
Keep the memo meaningful
The memo should always tell the reader what is being built. If it is a number, a string, or a collection, the first value should make that clear before the loop starts. That makes the method easier to follow and easier to debug, because each step of the fold has a visible purpose. A well-named memo helps the code read like a sentence instead of a math exercise. That matters when the block does more than just add numbers together.
Prefer small, explicit steps
inject can do a lot, but the clearest examples usually keep each step simple. If the block starts to hide several branches or nested calls, it can be worth splitting the work into a helper method or a few smaller pieces. The method stays most readable when the accumulation rule is obvious and the input shape is stable. That way, the code still feels like a fold over a sequence instead of a puzzle that only the original author can decode.
Errors
# Empty without initial returns nil
[].inject { |m, e| m + e } # => nil
# Empty with initial returns initial
[].inject(0) { |m, e| m + e } # => 0