From: Robert Klemme Date: 2007-02-24T18:55:05+09:00 Subject: Re: enum_cons with tail On 23.02.2007 20:50, 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] You want semantics that are different from #each_cons. #each_cons will give you a sliding window of n elements from the collection (see you example output). This can be used to e.g. smooth a measurement curve. > Is there anyway to do this? (The collection is an opened File, too > large to load entirely in memory.) Yes, see below (not the best implementation though). But maybe you want to change the algorithm that needs this. What are you trying to accomplish? > I don't have a clear grasp as to how internally Ruby treats a File as > Enumerable. You can cook your own version: require 'enumerator' module Enumerable def sub_range(n) ar = inject([]) do |rg, x| rg.push x rg.shift if rg.length > n yield *rg if rg.length == n rg end (n-1).times do ar.push nil ar.shift if ar.length > n yield *ar if ar.length == n end self end def each_add(n,&b) each(&b) n.times { b[nil] } self end def sub_range2(n,&b) to_enum(:each_add, n-1).enum_cons(n).each {|a| b[*a]} end end irb(main):036:0> [1].sub_range(3){|*x| p x} [1, nil, nil] => [1] irb(main):037:0> [1,2,3].sub_range(3){|*x| p x} [1, 2, 3] [2, 3, nil] [3, nil, nil] => [1, 2, 3] irb(main):038:0> (1..10).sub_range(3){|*x| p x} [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] => 1..10 irb(main):250:0> (1..1).sub_range2(3) {|*a| p a} [1, nil, nil] => nil irb(main):251:0> (1..10).sub_range2(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 Kind regards robert