each で隣の要素を参照
おぉ?こういうのは Enumerable モジュールに適当にメソッド追加とかでどうにでもなりそうな気がする。
module Enumerable def each_with_neighbor window = [:none, :none, :none] each do |item| window.push item window.shift if window[1] != :none yield *window end end window.push :none, window.shift if window[1] != :none yield *window end end end (0..10).each_with_neighbor do |prev, item, succ| puts "#{prev} #{item} #{succ}" end
てな感じでいいんでないかなぁ。変態的なのが好みならこういうのとか。なんかいろいろまずい気がするのでおすすめできない。
module Enumerable class Window attr_reader :prev, :succ def initialize(val, prev, succ) @val, @prev, @succ = val, prev, succ end def method_missing(name, *args) @val.send(name, *args) end def ==(x) @val == x end def inspect @val.inspect end end def each_with_neighbor(&block) def yield_with_neighbor(window, &block) item = Window.new(window[1], window[0], window[2]) item.instance_eval(&block) end window = [:none, :none, :none] each do |item| window.push item window.shift if window[1] != :none yield_with_neighbor(window, &block) end end window.push :none, window.shift if window[1] != :none yield_with_neighbor(window, &block) end end end (0..10).each_with_neighbor do |i| p [prev, i, succ] end
Array だけでいいなら zip を使うのが手軽ではある。
class Array def each_with_neighbor l = length ([nil] + self[0, l - 1]).zip(self, self[1, l - 1] + [nil]).each do |prev, item, succ| yield prev, item, succ end end end (0..10).to_a.each_with_neighbor do |prev, item, succ| p [prev, item, succ] end
いや、ていうか Array なら each_with_index で index を使って前後を取得すればいいのか。
組み込み変数を使うのはユーザレベルでスレッドローカル変数がないとマルチスレッド環境がなんとも。