From: Robert Klemme Date: 2009-06-12T20:18:29+09:00 Subject: Re: Idiomatic way to detect first/last iteration? 2009/6/11 Gary Wright : > > On Jun 11, 2009, at 12:43 PM, Kendall Gifford wrote: > >> Hi there, is there any recognized ruby idiomatic way for detecting >> when you're on the first and/or last iteration over a collection? Or, >> if not, anyone know of any tricky ways? > > > The following solution uses each_with_index internally but doesn't > depend on #first, #last, or #length. On a single item collection > it will report 'last' but not 'first'.  You'll have to decide if > that works in your case. Obviously you could change it to report > 'both' for a single item. > > Gary Wright > > > module Enumerable >  def each_with_position >    previous = sigil = Object.new >    each_with_index { |next_item, index| >      case index >      when 0 >        # do nothing >      when 1 >        yield(previous, 'first') >      else >        yield(previous, 'middle') >      end >      previous = next_item >    } >    yield(previous, 'last') unless previous == sigil >  end > end > >>> [1,2,3,4].each_with_position { |*x| p x } > [1, "first"] > [2, "middle"] > [3, "middle"] > [4, "last"] > => nil >>> [].each_with_position { |*x| p x } > => nil >>> [1].each_with_position { |*x| p x } > [1, "last"] > => nil Turns out we think along similar lines, although my solution is a bit more wasteful: module Enumerable # will yield elements along with # a symbol :first, :last, :middle or :only def each_special last = nil each do |x| if last yield *last last = [x, :middle] else # first iter last = [x, :first] end end yield last.first, last.last == :middle ? :last : :only if last self end end [ [], [1], [1,2], [1,2,3], [1,2,3,4,5], ].each do |en| p en en.each_special do |x,t| printf "%-10p %p\n", t, x end puts "end" end Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/