Enumerable#each_cons
Enumerator · Added in v1.8.7 · Updated March 16, 2026 · Enumerable The each_cons method groups consecutive elements together and iterates over each group. Unlike each_slice which takes elements in order from the start, each_cons always uses consecutive elements with no gaps.
How It Works
each_cons(n) takes n consecutive elements at a time:
collection.each_cons(n) { |group| block }
Each iteration gives you a slice of n consecutive elements. The last group may have fewer than n elements if the collection length isn’t evenly divisible.
Basic Usage
Process pairs of consecutive elements:
[1, 2, 3, 4, 5].each_cons(2) { |pair| p pair }
# => [1, 2]
# => [2, 3]
# => [3, 4]
# => [4, 5]
Triple groups:
[1, 2, 3, 4, 5].each_cons(3) { |group| p group }
# => [1, 2, 3]
# => [2, 3, 4]
# => [3, 4, 5]
Sliding Window Algorithms
Moving Averages
Calculate a 3-element moving average:
values = [10, 20, 30, 40, 50]
averages = values.each_cons(3).map { |window| window.sum.to_f / window.size }
# => [20.0, 30.0, 40.0]
Rate of Change
Find the difference between consecutive elements:
prices = [100, 105, 103, 110]
changes = prices.each_cons(2).map { |a, b| b - a }
# => [5, -2, 7]
Finding Peaks
Detect when a value is greater than both neighbors:
readings = [1, 3, 2, 5, 4, 6]
peaks = readings.each_cons(3).select { |prev, curr, next_| curr > prev && curr > next_ }
# => [[1, 3, 2], [2, 5, 4]]
# Peak values: 3, 5
Pairwise Comparisons
Compare every consecutive pair:
words = ["cat", "dog", "bird", "fish"]
words.each_cons(2) { |a, b| puts "#{a} -> #{b}" }
# cat -> dog
# dog -> bird
# bird -> fish
Sequential Analysis
Finding Consecutive Sequences
numbers = [1, 2, 3, 5, 6, 7, 9]
sequences = numbers.each_cons(2).chunk_while { |a, b| b == a + 1 }.to_a
# => [[1, 2, 3], [5, 6, 7], [9]]
Validating Ordered Data
Check if a list is sorted:
def sorted?(arr)
arr.each_cons(2).all? { |a, b| a <= b }
end
sorted?([1, 2, 3, 4]) # => true
sorted?([1, 3, 2, 4]) # => false
Running Differences
values = [100, 102, 105, 110]
diffs = values.each_cons(2).map { |a, b| [a, b, b - a] }
# => [[100, 102, 2], [102, 105, 3], [105, 110, 5]]
Window Size Considerations
Small Windows
Window size of 2 (pairs):
[1, 2, 3].each_cons(2).to_a
# => [[1, 2], [2, 3]]
Large Windows
(1..10).each_cons(4).to_a
# => [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8], [6, 7, 8, 9], [7, 8, 9, 10]]
Window Larger Than Collection
[1, 2, 3].each_cons(5).to_a
# => [] (no groups of 5)
Practical Examples
Comparing Adjacent List Items
tasks = ["wake up", "brush teeth", "eat breakfast", "go to work"]
tasks.each_cons(2) { |prev, curr| puts "After #{prev}: do #{curr}" }
# After wake up: do brush teeth
# After brush teeth: do eat breakfast
# After eat breakfast: do go to work
Polynomial Coefficients
coefficients = [1, -3, 3, -1] # (x - 1)^3
coefficients.each_cons(2).map { |a, b| b / a.to_f }
# => [-3.0, -1.0, -0.3333333333333333]
Text Analysis
Find consecutive capital letters:
text = "TheQuickBrownFox"
caps = text.chars.each_cons(2).select { |a, b| a =~ /[A-Z]/ && b =~ /[A-Z]/ }
# => [["Q", "B"], ["B", "F"]]
Comparison with Related Methods
| Method | Behavior |
|---|---|
each_cons | Consecutive elements, overlapping groups |
each_slice | Non-overlapping groups from start |
each_chunk | Groups based on block return value |
combination | All possible n-element combinations |
permutation | All possible orderings |
[1, 2, 3].each_cons(2).to_a # => [[1, 2], [2, 3]] (consecutive)
[1, 2, 3].each_slice(2).to_a # => [[1, 2], [3]] (non-overlapping)
[1, 2, 3].combination(2).to_a # => [[1, 2], [1, 3], [2, 3]] (all combos)
Return Value
Returns an Enumerator if no block is given:
enum = [1, 2, 3, 4].each_cons(2)
# => #<Enumerator: [1, 2, 3, 4]:each_cons(2)>
enum.to_a
# => [[1, 2], [2, 3], [3, 4]]
Edge Cases
Empty collection:
[].each_cons(2).to_a
# => []
Single element:
[1].each_cons(2).to_a
# => []
Nil values are included:
[1, nil, 3].each_cons(2).to_a
# => [[1, nil], [nil, 3]]
See Also
Enumerable#each_slice— non-overlapping consecutive groupsEnumerable#chunk_while— group by consecutive conditionEnumerable#each_with_object— iterate with accumulatorArray#combination— all possible combinationsArray#zip— combine arrays element-wise