From: Mark Hubbart Date: 2004-11-05T20:48:34+09:00 Subject: Re: Cleaner way to do this? On Fri, 5 Nov 2004 12:34:12 +0900, Harry Ohlsen wrote: > > From: Zach Dennis [mailto:zdennis@mktec.com] > > Sent: Friday, 5 November 2004 14:01 > > > > Subject: Re: Cleaner way to do this? > > > If your friend knows the processing he wants to do on the first > > element, why not just keep it simple... > > > arr = [1,2,3,4,5] > > process = proc{ |e| print e }.call( arr[0] ) > > arr[1...arr.length].each do |e| > > print ", #{e}" > > end > > Agreed :-). > > I think the original discussion came about because he was interested in > iterators and wanted to understand how one might write an efficient > iterator that allowed for handling of special cases, like doing > something different with the first or last entry in a collection. > > I didn't like to dampen that kind of enthusiasm. Well, after some interesting sidetracked thoughts, I came up with this form: [1,2,3,4].do_first{|n| print n}.then_rest{|n| print ", ",n} 1, 2, 3, 4 ==>[1, 2, 3, 4] Then this quickly hacked implementation, using singleton methods to turn the first block into a proxy quasi-enumerable object. module Enumerable def do_first(&block) class << block def then_rest first_done = nil @enum.each do |arg| yield arg if first_done first_done ||= [self[arg]] end end end this = self block.instance_eval{@enum = this} block end end I'm sorta perversely proud of this code. I shouldn't be, but I think I am. I almost didn't post this, but I just had to... A proper implementation might be possible using a special ProxyEnumerable class, which delegates to the real enumerable that you pass it on initialization. cheers, Mark