From: "Guy N. Hurst" Date: 2002-03-19T20:30:56+09:00 Subject: Re: How to implement each_continuous_range andrew queisser wrote: > > I'd like to implement an iterator that returns all ranges of > successive elements of an array. If an array consists of [1,2,3,5,6] > the iterator should return 1,3 and 5,6. I don't care whether the > iterator returns an array with two elements or two values. So far I > have this: > > #---------------------------------------- > x = [ 1, 2, 3, 4, 7, 8, 12, 15, 16, 22 ] > > class Array > def each_cont_range > r0 = 0 > for i in 0..length()-2 > if (self[i+1] != self[i].succ) > yield(self[r0], self[i]) > r0 = i+1 > end > end > yield(self[r0], self[-1]) > end > end > > x.each_cont_range { |r0, r1| print "range #{r0} to #{r1}\n" } > #--------------------------------------------------- > > It works but it isn't pretty. I tried to use an inject function but > didn't get anywhere. Suggestions for improvement? Are there any > built-in ways of doing this? > I don't think there is any built-in way to do this, but here is my contribution (I call it each_range): class Array def each_range a=self.dup a.each_index{|i| yield(a[i],(a.slice!(i) while a[i+1]==a[i].succ;a[i]))} end end irb preview: =========== irb(main):001:0> class Array irb(main):002:1> def each_range irb(main):003:2> a=self.dup irb(main):004:2> a.each_index{|i| yield(a[i],(a.slice!(i) while a[i+1]==a[i].succ;a[i]))} irb(main):005:2> end irb(main):006:1> end nil irb(main):007:0> x = [ 1, 2, 3, 4, 7, 8, 12, 15, 16, 22 ] [1, 2, 3, 4, 7, 8, 12, 15, 16, 22] irb(main):008:0> x.each_range { |r0, r1| puts "range #{r0} to #{r1}" } range 1 to 4 range 7 to 8 range 12 to 12 range 15 to 16 range 22 to 22 [4, 8, 12, 16, 22] irb(main):009:0> I made it return arrays of start,end pairs because you used it that way, but it is a simple matter to return a Range object, too. Guy N. Hurst