Ruby each_cons
As methods go, each cons is pretty mysterious. I’m not even sure exactly what you would use it for. However, in the interest of science, here is a brief discussion.
UPDATE
Gregory Brown, who wrote the Prawn PDF library, suggests that:
“In general each_cons is useful when you need a sliding window of size n across a dataset.”
/update
Usage
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# Necessary >> require "enumerator" => true # Theory >> [*('a'..'g')].each_cons(2){|set| p set.join(" and ")} "a and b" "b and c" "c and d" "d and e" "e and f" "f and g" => nil # Iterates the given block for each array of consecutive <n> elements. # Practice ???????? # Documentation (1..10).each_cons(3) {|a| p a} # outputs below [1, 2, 3] [2, 3, 4] [3, 4, 5] [4, 5, 6] [5, 6, 7] [6, 7, 8] [7, 8, 9] [8, 9, 10] |
Real life
The Prawn pdf library uses each_cons like so
1 2 3 4 5 6 |
def polygon(*points) move_to points[0] (points << points[0]).each_cons(2) do |p1,p2| line_to(*p2) end end |
update
Gregory Brown says:
%Q{
I think you may have been confused by my ugly code there. I have
replaced it with:
1 2 3 4 5 6 |
def polygon(*points) move_to points[0] (points[1..-1] << points[0]).each do |point| line_to(*point) end end |
The reason why it’s not needed is because we draw the lines from point
to point.
But if we were drawing them segment by segment, it’d make sense.
1 2 3 4 5 |
>> [[1,2],[3,4],[5,6],[1,2]].each_cons(2) { |a| p a } [[1, 2], [3, 4]] [[3, 4], [5, 6]] [[5, 6], [1, 2]] |
I imagine I had refactored a line p1, p2 call down to just line_to(p2)
without fixing the each_cons()… sorry about that.
In general each_cons is useful when you need a sliding window of size
n across a dataset.
Here’s a more reasonable usage, for solving a simple tree-traversal
problem:
http://blog.majesticseacreature.com/archives/2008.10/euler_67.html
}
As far as I can google, prawn seemed to be the only usage of each_cons in the wild. Now that he’s refactored it, it appears that nothing on github will be using it.
If you’re curious, I’ve posted a question on the ruby mailing list here about what this is actually for.
At any rate, here’s the…
Implementation
1 2 3 4 5 6 7 8 9 10 |
def each_cons(n, &block) array = [] elements = self.to_a while elements.size > 0 do array << elements[0,n] if elements[0,n].size == n elements.shift end array.each { |set| yield set } nil end |
Rubinius begins by creating an empty array, then forcing the object to be an array, if it isn’t already.
Next, it iterates over each element in the enumerable object, adding a sub array of elements with the length of n.
Next, it iterates over each of the new array’s elements, passing the set to the block.
Finally, it returns nil.
- Person:
- Programming Language:


Recent comments
1 year 23 weeks ago
1 year 23 weeks ago
1 year 25 weeks ago
1 year 27 weeks ago
1 year 42 weeks ago
1 year 45 weeks ago
1 year 45 weeks ago
1 year 45 weeks ago
1 year 46 weeks ago
1 year 48 weeks ago