Enumerable#chunk
Enumerator · Added in v1.9 · Updated March 16, 2026 · Enumerable The chunk method groups consecutive elements that return the same value from the block. It’s ideal for processing runs of identical values, state changes, or categorized data without loading everything into memory first.
How It Works
chunk passes each element to the block and groups consecutive elements with the same return value:
enumerable.chunk { |element| block_value }
# Returns an Enumerator of [block_value, elements_array] pairs
Basic Usage
Group consecutive even and odd numbers:
[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].chunk { |n| n.even? }.to_a
# => [[false, [3, 1]], [true, [4]], [false, [1, 5, 9]], [true, [2, 6]], [false, [5, 3, 5]]]
Practical Examples
Processing Log Files
Group consecutive log entries by level:
log_levels = [:info, :info, :warn, :error, :error, :info, :debug, :debug]
log_levels.chunk { |level| level }.each do |level, entries|
puts "#{level}: #{entries.count} entries"
end
# Output:
# info: 2 entries
# warn: 1 entries
# error: 2 entries
# info: 1 entries
# debug: 2 entries
Grouping Consecutive Letters
Find runs of consecutive characters in a string:
"aaabbbccdaa".chars.chunk(&:itself).map { |char, arr| [char, arr.length] }
# => [["a", 3], ["b", 3], ["c", 2], ["d", 1], ["a", 2]]
Processing CSV Data
Group rows by a category column:
rows = [
{ category: "fruit", name: "apple" },
{ category: "fruit", name: "banana" },
{ category: "vegetable", name: "carrot" },
{ category: "fruit", name: "date" },
{ category: "vegetable", name: "eggplant" }
]
rows.chunk { |row| row[:category] }.each do |category, items|
puts "#{category}: #{items.map { |i| i[:name] }.join(', ')}"
end
# Output:
# fruit: apple, banana
# vegetable: carrot
# fruit: date
# vegetable: eggplant
Finding State Changes
Track when a status changes in a sequence:
statuses = [:idle, :idle, :running, :running, :running, :complete, :idle, :idle]
statuses.chunk_while { |before, after| before == after }.each do |run|
puts "Status: #{run.first}, Duration: #{run.length}"
end
# Output:
# Status: idle, Duration: 2
# Status: running, Duration: 3
# Status: complete, Duration: 1
# Status: idle, Duration: 2
Grouping Test Results
Process test results in batches:
results = [:pass, :pass, :fail, :fail, :pass, :pass, :pass]
results.chunk { |r| r == :pass ? :passed : :failed }.each do |status, tests|
puts "#{status}: #{tests.count} tests"
end
# Output:
# passed: 2 tests
# failed: 2 tests
# passed: 3 tests
Using :underscore to Skip Elements
The special :underscore symbol tells chunk to skip that element entirely:
[1, 2, 3, :skip, 4, 5, 6, :skip, 7].chunk { |x| x == :skip ? :_skip : x.even? }.to_a
# => [[false, [1]], [true, [2]], [false, [3]], [true, [4, 6]], [false, [7]]]
This is useful for filtering out certain values while still grouping the rest.
Comparison with Related Methods
| Method | What It Does |
|---|---|
chunk | Groups consecutive elements by block return value |
group_by | Groups all elements regardless of order/consecutive |
slice_when | Splits when block returns true between elements |
chunk_while | Like slice_when but creates Enumerator |
# chunk - only groups consecutive elements
[1, 2, 1, 2].chunk { |x| x.odd? }.to_a
# => [[true, [1]], [false, [2]], [true, [1]], [false, [2]]]
# group_by - groups all matching elements together
[1, 2, 1, 2].group_by { |x| x.odd? }
# => {true => [1, 1], false => [2, 2]}
Return Value
Returns an Enumerator. Use to_a to get an array, or iterate directly:
[1, 2, 2, 3, 3, 3].chunk { |n| n }
# => #<Enumerator: [1, 2, 2, 3, 3, 3]:chunk>
[1, 2, 2, 3, 3, 3].chunk { |n| n }.each { |k, v| puts "#{k}: #{v}" }
# 1: [1]
# 2: [2, 2]
# 3: [3, 3, 3]
Edge Cases
Empty collections return an empty enumerator:
[].chunk { |x| x }.to_a
# => []
Single element:
[42].chunk { |x| x }.to_a
# => [[42, [42]]]
All same values:
[1, 1, 1, 1].chunk { |x| x }.to_a
# => [[1, [1, 1, 1, 1]]]
All different values:
[1, 2, 3, 4].chunk { |x| x }.to_a
# => [[1, [1]], [2, [2]], [3, [3]], [4, [4]]]
See Also
Enumerable#group_by— group all elements by valueEnumerable#reduce— accumulate values into a single resultEnumerable#flat_map— transform and flatten in one passArray#flatten— merge nested arraysArray#compact— remove nil values from arrays