with_index
Rubyの外部イテレータ使えない…。ちなみに以下のサンプルは1.9.0でテストした。
> (1..4).each.with_index.to_a => [[1, 0], [2, 1], [3, 2], [4, 3]] > e = (1..4).each.with_index => #<Enumerable::Enumerator:0xc8c404> > e.next 1
何でe.nextで[1, 0]でなくて1が返るのかな?with_indexの意味がない。もちろん内部イテレータだったら以下のように問題ない。
> (1..4).each.with_index {|v, i| * puts("#{v}, #{i}") > } 1, 0 2, 1 3, 2 4, 3 => 1..4
そこで、Pythonのenumerate()関数相当のものを作成してみた。
> def enumerate(seq) > i = 0 > seq.each {|v| * yield [i, v] > i += 1 > } > end => nil > enumerate(1..4) {|i, v| * puts("#{i}, #{v}") > } 0, 1 1, 2 2, 3 3, 4 => 1..4
Rubyでyield使うと内部イテレータになってしまう。forと組み合わせるにはPythonのような外部イテレータを返すようにenumerate()を作成したい。調べてみたらRubyで外部ジェネレータを作成するにはgeneratorモジュールを使うみたい。リファレンスマニュアルを見ながらサンプルを試したら、1.9.0ではエラーが発生した。リファレンスマニュアルのサンプルが更新されていない。どうすれば良いのだろう?
- ライブラリ一覧: class Generator (http://doc.loveruby.net/refm/api/view/class/Generator)
とりあえず、1.8.6ではできたので貼っておく。
> requre 'generator' => true > def enumerate(seq) > i = 0 > Generator.new {|g| * seq.each {|v| * g.yield [i, v] > i += 1 > } > } > end => nil > for i, v in enumerate(1..4) > puts("#{i}, #{v}") > end 0, 1 1, 2 2, 3 3, 4 => #<Generator:0x2955bf8 ...(略)...>
Pythonぽくてなかなか良い。