From: Olivier Renaud Date: 2007-02-24T09:32:08+09:00 Subject: Re: enum_cons with tail Le vendredi 23 f�vrier 2007 22:25, S. Robert James a �crit�: > I'm not sure how to do either of those. Like I said, this is a File, > not a true Array. (The magic of Ruby makes it Enumerable, but I > haven't mastered that magic yet.) > > On Feb 23, 3:54 pm, "Kenosis" wrote: > > On Feb 23, 11:50 am, "S. Robert James" wrote: > > > enum_cons chops off the tail of the collection, if it isn't evenly > > > divisble: > > > > > > e.g.: > > > (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] > > > > > > I'd also like to get: > > > [9, 10, nil] > > > [10, nil, nil] > > > > > > Is there anyway to do this? (The collection is an opened File, too > > > large to load entirely in memory.) > > > > > > I don't have a clear grasp as to how internally Ruby treats a File as > > > Enumerable. > > > > Not that I am aware of. Two things come to mind. 1) You could append > > nil items to your array to make it evenly divisable, 2) you could > > extend arrary with your own each_cons that does what you want. Hope > > this is at least some help. Perhaps others will know a more direct > > way to accomplish what you seek. > > > > Ken It's not important whether the enumeration is done on a File or not. As long as the object has a meaningful "each" method, you can enumerate it any way you want. Your modified enum_const can be accomplished by wrapping the original #each_cons in a home-made method. So first, here is a wrapping method that just does nothing more than the original : module Enumerable def each_cons_2(n, &block) each_cons(n) {|a| block.call(a) } end end Then, we just need to get the last value returned by the called block, to be able to manually continue the iteration the way you want (adding nils) : module Enumerable def each_cons_2(n, &block) a = nil each_cons(n) {|a| block.call(a) } (n-1).times { a.shift; a << nil; yield a } nil end end The trick here, is to declare the variable "a" before the block, so that this a is the same than the |a| in the block. Doing so, we end up after the block with "a" containing the value returned by the last call of the block (ie, the array [8,9,10] in your example). Then, we continue the iteration, modifying and yielding this array n-1 times. (1..10).each_cons_2(3) {|a| p a} [1, 2, 3] [2, 3, 4] [3, 4, 5] [4, 5, 6] [5, 6, 7] [6, 7, 8] [7, 8, 9] [8, 9, 10] [9, 10, nil] [10, nil, nil] => nil -- Olivier Renaud