Enumerable#each_with_object
Object · Added in v1.8.6 · Updated March 15, 2026 · Enumerable The each_with_object method iterates over a collection, passing each element and a mutable object you provide. Unlike inject/reduce, the accumulator object is returned unchanged at the end — you modify it inside the block.
How It Works
Unlike inject/reduce where the return value of the block becomes the accumulator, each_with_object keeps your object intact and lets you mutate it directly:
result = collection.each_with_object(initial_object) { |element, accumulator|
# modify accumulator in place
}
The object you pass is the one that gets returned at the end.
Basic Usage
Building an array of doubled values:
numbers = [1, 2, 3, 4, 5]
doubled = numbers.each_with_object([]) { |n, arr| arr << n * 2 }
# => [2, 4, 6, 8, 10]
Building a hash from an array:
words = ["apple", "banana", "cherry"]
lengths = words.each_with_object({}) { |word, hash| hash[word] = word.length }
# => {"apple"=>5, "banana"=>6, "cherry"=>6}
Why Use Each_with_object Over Inject?
The key difference is mutability. With inject/reduce, the accumulator is reassigned each iteration:
# inject - accumulator is reassigned each time
[1, 2, 3].inject(0) { |acc, n| acc + n }
# => 6 (acc gets new value each iteration)
With each_with_object, you start with a specific object and mutate it:
# each_with_object - you control the exact object returned
[1, 2, 3].each_with_object([]) { |n, arr| arr << n }
# => [1, 2, 3] (the exact array you passed in, now populated)
Practical Examples
Grouping Elements by a Criteria
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
grouped = numbers.each_with_object({ even: [], odd: [] }) do |n, hash|
n.even? ? hash[:even] << n : hash[:odd] << n
end
# => {even=>[2, 4, 6, 8, 10], odd=>[1, 3, 5, 7, 9]}
Building a Nested Hash
orders = [
{ customer: "Alice", item: "Book", price: 15 },
{ customer: "Bob", item: "Pen", price: 3 },
{ customer: "Alice", item: "Pen", price: 2 }
]
by_customer = orders.each_with_object(Hash.new { |h, k| h[k] = [] }) do |order, hash|
hash[order[:customer]] << { item: order[:item], price: order[:price] }
end
# => {"Alice"=>[{:item=>"Book", :price=>15}, {:item=>"Pen", :price=>2}],
# "Bob"=>[{:item=>"Pen", :price=>3}]}
Collecting Multiple Results at Once
data = [1, 2, 3, 4, 5]
results = data.each_with_object({ positives: [], negatives: [], zeros: [] }) do |n, hash|
if n > 0
hash[:positives] << n
elsif n < 0
hash[:negatives] << n
else
hash[:zeros] << n
end
end
# => {positives:[1, 2, 3, 4, 5], negatives:[], zeros:[]}
Flattening Nested Structures
nested = [[1, 2], [3, 4], [5, 6]]
flat = nested.each_with_object([]) { |subarr, arr| arr.concat(subarr) }
# => [1, 2, 3, 4, 5, 6]
With Hashes
stock = { apples: 5, oranges: 3, bananas: 0 }
out_of_stock = stock.each_with_object([]) { |(k, v), arr| arr << k if v.zero? }
# => [:bananas]
# Transform a hash into another hash
prices = { apple: 1, banana: 2, cherry: 5 }
doubled = prices.each_with_object({}) { |(k, v), h| h[k] = v * 2 }
# => {:apple=>2, :banana=>4, :cherry=>10}
Common Mistakes
Forgetting the Return Value
Unlike inject, the block return value does not matter:
# This works fine, even though block returns nil
[1, 2, 3].each_with_object([]) { |n, arr| arr << n if n.even? }
# => [2]
# The accumulator object is returned, not the block result
Confusing Parameter Order
Remember: element comes first, then the accumulator:
# Wrong - this is a common mistake
[1, 2, 3].each_with_object([]) { |arr, n| arr << n }
# => NoMethodError: undefined method `<<' for nil:NilClass
# Correct - element, then accumulator
[1, 2, 3].each_with_object([]) { |n, arr| arr << n }
# => [1, 2, 3]
Performance Notes
each_with_objectcreates your accumulator object once, then modifies it- Avoid creating new objects inside the block if performance matters
- For simple numeric accumulation,
inject/reduceis often clearer
Return Value
Always returns the object you passed in, regardless of what happens in the block:
result = [1, 2, 3].each_with_object({}) { |n, h| h[n] = n * 2 }
result # => {1=>2, 2=>4, 3=>6}
# The exact same object you passed as the second argument
See Also
Array#map— transform each element into a new arrayArray#inject— accumulate values by reassigningEnumerable#group_by— group elements by a criteriaHash#each— iterate over key-value pairs